Commit cd7b8a03 authored by Eric Noulard's avatar Eric Noulard Committed by Brad King
Browse files

CPack: Refactor API in order to handle multi-file packages

The multi-argument CompressFiles(...) method has been replace by the
no-argument PackageFiles() method and 3 more member variables.  This
will enable implemention of multi-package generators.  Now each specific
generator (which overloads PackageFiles()) may decide to change the name
and/or the number of generated package files.
parent 7c20f7b2
......@@ -166,8 +166,7 @@ int cmCPackArchiveGenerator::InitializeInternal()
return this->Superclass::InitializeInternal();
}
int cmCPackArchiveGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackArchiveGenerator::PackageFiles()
{
int res = ARCHIVE_OK;
#define CHECK_ARCHIVE_ERROR(res, msg) \
......@@ -180,14 +179,15 @@ int cmCPackArchiveGenerator::CompressFiles(const char* outFileName,
<< "\n"); \
}
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: "
<< (toplevel ? toplevel : "(NULL)") << std::endl);
<< toplevel << std::endl);
// create a new archive
struct archive* a = archive_write_new();
// Set the compress and archive types for the archive
SetArchiveType(a, this->Compress, this->Archive);
// Open binary stream
cmGeneratedFileStream* gf = new cmGeneratedFileStream;
gf->Open(outFileName, false, true);
gf->Open(packageFileNames[0].c_str(), false, true);
StreamData data(gf, this);
// pass callbacks to archive_write_open to handle stream
res = archive_write_open(a,
......@@ -204,13 +204,13 @@ int cmCPackArchiveGenerator::CompressFiles(const char* outFileName,
CHECK_ARCHIVE_ERROR(res, "archive_read_disk_set_standard_lookup:");
std::vector<std::string>::const_iterator fileIt;
std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
cmSystemTools::ChangeDirectory(toplevel);
cmSystemTools::ChangeDirectory(toplevel.c_str());
for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
{
// create a new entry for each file
struct archive_entry *entry = archive_entry_new();
// Get the relative path to the file
std::string rp = cmSystemTools::RelativePath(toplevel, fileIt->c_str());
std::string rp = cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str());
// Set the name of the entry to the file name
archive_entry_set_pathname(entry, rp.c_str());
res = archive_read_disk_entry_from_file(disk, entry, -1, 0);
......
......@@ -37,8 +37,7 @@ public:
protected:
virtual int InitializeInternal();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
virtual const char* GetOutputExtension() = 0;
CompressType Compress;
ArchiveType Archive;
......
......@@ -53,10 +53,8 @@ const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
}
//----------------------------------------------------------------------
int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackBundleGenerator::PackageFiles()
{
(void) files;
// Get required arguments ...
const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
......@@ -167,5 +165,5 @@ int cmCPackBundleGenerator::CompressFiles(const char* outFileName,
cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
}
return this->CreateDMG(toplevel, outFileName);
return this->CreateDMG(toplevel.c_str(), packageFileNames[0].c_str());
}
......@@ -31,8 +31,7 @@ public:
protected:
virtual int InitializeInternal();
virtual const char* GetPackagingInstallPrefix();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
std::string InstallPrefix;
};
......
......@@ -41,8 +41,7 @@ int cmCPackCygwinBinaryGenerator::InitializeInternal()
}
//----------------------------------------------------------------------
int cmCPackCygwinBinaryGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackCygwinBinaryGenerator::PackageFiles()
{
std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
packageName += "-";
......@@ -70,12 +69,10 @@ int cmCPackCygwinBinaryGenerator::CompressFiles(const char* outFileName,
ofs << manifest << "\n";
}
// add the manifest file to the list of all files
std::vector<std::string> filesWithManifest = files;
filesWithManifest.push_back(manifestFile);
files.push_back(manifestFile);
// create the bzip2 tar file
return this->Superclass::CompressFiles(outFileName, toplevel,
filesWithManifest);
return this->Superclass::PackageFiles();
}
const char* cmCPackCygwinBinaryGenerator::GetOutputExtension()
......
......@@ -30,8 +30,7 @@ public:
virtual ~cmCPackCygwinBinaryGenerator();
protected:
virtual int InitializeInternal();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
virtual const char* GetOutputExtension();
std::string OutputExtension;
};
......
......@@ -48,21 +48,19 @@ int cmCPackCygwinSourceGenerator::InitializeInternal()
}
//----------------------------------------------------------------------
int cmCPackCygwinSourceGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackCygwinSourceGenerator::PackageFiles()
{
// Create a tar file of the sources
std::string packageDirFileName
= this->GetOption("CPACK_TEMPORARY_DIRECTORY");
packageDirFileName += ".tar.bz2";
packageFileNames[0] = packageDirFileName;
std::string output;
// skip one parent up to the cmCPackTarBZip2Generator
// to create tar.bz2 file with the list of source
// files
this->Compress = BZIP2;
if ( !this->cmCPackTarBZip2Generator::
CompressFiles(packageDirFileName.c_str(),
toplevel, files) )
if ( !this->cmCPackTarBZip2Generator::PackageFiles() )
{
return 0;
}
......@@ -135,21 +133,25 @@ int cmCPackCygwinSourceGenerator::CompressFiles(const char* outFileName,
patchFile += "/";
patchFile += cmSystemTools::GetFilenameName(
this->GetOption("CPACK_CYGWIN_PATCH_FILE"));
std::vector<std::string> outerFiles;
std::string file = cmSystemTools::GetFilenameName(compressOutFile);
std::string sourceTar = cmSystemTools::GetFilenamePath(compressOutFile);
sourceTar += "/";
sourceTar += file;
/* reset list of file to be packaged */
files.clear();
// a source release in cygwin should have the build script used
// to build the package, the patch file that is different from the
// regular upstream version of the sources, and a bziped tar file
// of the original sources
outerFiles.push_back(buildScript);
outerFiles.push_back(patchFile);
outerFiles.push_back(sourceTar);
if ( !this->cmCPackTarBZip2Generator::
CompressFiles(outerTarFile.c_str(),
tmpDir.c_str(), outerFiles) )
files.push_back(buildScript);
files.push_back(patchFile);
files.push_back(sourceTar);
/* update the name of the produced package */
packageFileNames[0] = outerTarFile;
/* update the toplevel dir */
toplevel = tmpDir;
if ( !this->cmCPackTarBZip2Generator::PackageFiles() )
{
return 0;
}
......
......@@ -31,8 +31,7 @@ public:
protected:
const char* GetPackagingInstallPrefix();
virtual int InitializeInternal();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
virtual const char* GetOutputExtension();
std::string InstallPrefix;
std::string OutputExtension;
......
......@@ -48,9 +48,7 @@ int cmCPackDebGenerator::InitializeInternal()
}
//----------------------------------------------------------------------
int cmCPackDebGenerator::CompressFiles(const char* outFileName,
const char* toplevel,
const std::vector<std::string>& files)
int cmCPackDebGenerator::PackageFiles()
{
this->ReadListFile("CPackDeb.cmake");
const char* cmakeExecutable = this->GetOption("CMAKE_COMMAND");
......@@ -141,7 +139,7 @@ int cmCPackDebGenerator::CompressFiles(const char* outFileName,
// now add all directories which have to be compressed
// collect all top level install dirs for that
// e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would give /usr and /opt
size_t topLevelLength = strlen(toplevel);
size_t topLevelLength = toplevel.length();
std::set<std::string> installDirs;
for (std::vector<std::string>::const_iterator fileIt = files.begin();
fileIt != files.end(); ++ fileIt )
......@@ -160,7 +158,7 @@ int cmCPackDebGenerator::CompressFiles(const char* outFileName,
std::string output;
int retVal = -1;
int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
&retVal, toplevel, this->GeneratorVerbose, 0);
&retVal, toplevel.c_str(), this->GeneratorVerbose, 0);
if ( !res || retVal )
{
......@@ -196,7 +194,7 @@ int cmCPackDebGenerator::CompressFiles(const char* outFileName,
//std::string output;
//int retVal = -1;
res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
&retVal, toplevel, this->GeneratorVerbose, 0);
&retVal, toplevel.c_str(), this->GeneratorVerbose, 0);
// debian md5sums entries are like this:
// 014f3604694729f3bf19263bac599765 usr/bin/ccmake
// thus strip the full path (with the trailing slash)
......@@ -237,7 +235,7 @@ int cmCPackDebGenerator::CompressFiles(const char* outFileName,
}
}
res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output,
&retVal, toplevel, this->GeneratorVerbose, 0);
&retVal, toplevel.c_str(), this->GeneratorVerbose, 0);
if ( !res || retVal )
{
......@@ -263,7 +261,7 @@ int cmCPackDebGenerator::CompressFiles(const char* outFileName,
arFiles.push_back(topLevelString + "debian-binary");
arFiles.push_back(topLevelString + "control.tar.gz");
arFiles.push_back(topLevelString + "data.tar.gz");
res = ar_append(outFileName, arFiles);
res = ar_append(packageFileNames[0].c_str(), arFiles);
if ( res!=0 )
{
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
......
......@@ -33,8 +33,7 @@ public:
protected:
virtual int InitializeInternal();
virtual int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
virtual int PackageFiles();
virtual const char* GetOutputExtension() { return ".deb"; }
};
......
......@@ -104,12 +104,10 @@ const char* cmCPackDragNDropGenerator::GetOutputExtension()
}
//----------------------------------------------------------------------
int cmCPackDragNDropGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackDragNDropGenerator::PackageFiles()
{
(void) files;
return this->CreateDMG(toplevel, outFileName);
return this->CreateDMG(toplevel, packageFileNames[0]);
}
//----------------------------------------------------------------------
......
......@@ -29,8 +29,7 @@ public:
protected:
virtual int InitializeInternal();
virtual const char* GetOutputExtension();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
bool CopyFile(cmOStringStream& source, cmOStringStream& target);
bool RunCommand(cmOStringStream& command, std::string* output = 0);
......
......@@ -100,6 +100,7 @@ int cmCPackGenerator::PrepareNames()
}
std::string destFile = pdir;
this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile.c_str());
destFile += "/" + outName;
std::string outFile = topDirectory + "/" + outName;
this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory.c_str());
......@@ -843,7 +844,7 @@ int cmCPackGenerator::DoPackage()
}
// The files to be installed
std::vector<std::string> files = gl.GetFiles();
files = gl.GetFiles();
// For component installations, determine which files go into which
// components.
......@@ -866,34 +867,59 @@ int cmCPackGenerator::DoPackage()
}
}
if ( !this->CompressFiles(tempPackageFileName,
tempDirectory, files) || cmSystemTools::GetErrorOccuredFlag())
packageFileNames.clear();
/* Put at least one file name into the list of
* wanted packageFileNames. The specific generator
* may update this during PackageFiles.
* (either putting several names or updating the provided one)
*/
packageFileNames.push_back(tempPackageFileName);
toplevel = tempDirectory;
if ( !this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag())
{
cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory"
<< std::endl);
return 0;
}
cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Finalize package" << std::endl);
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Copy final package: "
<< (tempPackageFileName ? tempPackageFileName : "(NULL)" )
<< " to "
<< (packageFileName ? packageFileName : "(NULL)")
<< std::endl);
if ( !cmSystemTools::CopyFileIfDifferent(tempPackageFileName,
packageFileName) )
/*
* Copy the generated packages to final destination
* - there may be several of them
* - the initially provided name may have changed
* (because the specific generator did 'normalize' it)
*/
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Copying final package(s) ["
<<packageFileNames.size()
<<"]:"<<std::endl);
std::vector<std::string>::iterator it;
/* now copy package one by one */
for (it=packageFileNames.begin();it!=packageFileNames.end();++it)
{
cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the package: "
<< (tempPackageFileName ? tempPackageFileName : "(NULL)" )
<< " to "
<< (packageFileName ? packageFileName : "(NULL)")
<< std::endl);
return 0;
std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
tempPackageFileName = it->c_str();
tmpPF += "/"+cmSystemTools::GetFilenameName(*it);
packageFileName = tmpPF.c_str();
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy final package(s): "
<< (tempPackageFileName ? tempPackageFileName : "(NULL)" )
<< " to "
<< (packageFileName ? packageFileName : "(NULL)")
<< std::endl);
if ( !cmSystemTools::CopyFileIfDifferent(tempPackageFileName,
packageFileName) )
{
cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the package: "
<< (tempPackageFileName ? tempPackageFileName : "(NULL)" )
<< " to "
<< (packageFileName ? packageFileName : "(NULL)")
<< std::endl);
return 0;
}
cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- package: "
<< packageFileName
<< " generated." << std::endl);
}
cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Package "
<< (packageFileName ? packageFileName : "(NULL)")
<< " generated." << std::endl);
return 1;
}
......@@ -984,12 +1010,8 @@ int cmCPackGenerator::SetCMakeRoot()
}
//----------------------------------------------------------------------
int cmCPackGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackGenerator::PackageFiles()
{
(void)outFileName;
(void)toplevel;
(void)files;
return 0;
}
......
......@@ -55,13 +55,22 @@ class cmCPackGenerator : public cmObject
public:
cmTypeMacro(cmCPackGenerator, cmObject);
/**
* If verbose then more informaiton is printed out
* If verbose then more information is printed out
*/
void SetVerbose(bool val) { this->GeneratorVerbose = val; }
/**
* Do the actual processing. Subclass has to override it.
* Return 0 if error.
* Do the actual whole package processing.
* Subclass may redefine it but its usually enough
* to redefine @ref PackageFiles, because in fact
* this method do call:
* - PrepareName
* - clean-up temp dirs
* - InstallProject (with the appropriate method)
* - prepare list of files and/or components to be package
* - PackageFiles
* - Copy produced packages at the expected place
* @return 0 if error.
*/
virtual int DoPackage();
......@@ -94,13 +103,32 @@ public:
bool ReadListFile(const char* moduleName);
protected:
/**
* Prepare common used names by inspecting
* several CPACK_xxx var values.
*/
int PrepareNames();
/**
* Install the project using appropriate method.
*/
int InstallProject();
int CleanTemporaryDirectory();
virtual const char* GetOutputExtension() { return ".cpack"; }
virtual const char* GetOutputPostfix() { return 0; }
virtual int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
/**
* Package the list of files and/or components which
* has been prepared by the beginning of DoPackage.
* @pre @ref toplevel has been filled-in
* @pre the list of file @ref files has been populated
* @pre packageFileNames contains at least 1 entry
* @post packageFileNames may have been updated and contains
* the list of packages generated by the specific generator.
*/
virtual int PackageFiles();
virtual const char* GetInstallPath();
virtual const char* GetPackagingInstallPrefix();
......@@ -134,11 +162,42 @@ protected:
std::string InstallPath;
/**
* The list of package file names.
* At beginning of DoPackage the (generic) generator will populate
* the list of desired package file names then it will
* call the redefined method PackageFiles which is may
* either use this set of names (usually on entry there should be
* only a single name) or update the vector with the list
* of created package file names.
*/
std::vector<std::string> packageFileNames;
/**
* The directory where all the files to be packaged reside.
* If the installer support components there will be one
* sub-directory for each component. In those directories
* one will find the file belonging to the specified component.
*/
std::string toplevel;
/**
* The complete list of files to be packaged.
* This list will be populated by DoPackage before
* PackageFiles is called.
*/
std::vector<std::string> files;
std::string CPackSelf;
std::string CMakeSelf;
std::string CMakeRoot;
std::map<std::string, cmCPackInstallationType> InstallationTypes;
/**
* The set of components.
* If component installation is supported then this map
* contains the component specified in CPACK_COMPONENTS_ALL
*/
std::map<std::string, cmCPackComponent> Components;
std::map<std::string, cmCPackComponentGroup> ComponentGroups;
......
......@@ -43,11 +43,10 @@ cmCPackNSISGenerator::~cmCPackNSISGenerator()
}
//----------------------------------------------------------------------
int cmCPackNSISGenerator::CompressFiles(const char* outFileName,
const char* toplevel, const std::vector<std::string>& files)
int cmCPackNSISGenerator::PackageFiles()
{
(void)outFileName; // TODO: Fix nsis to force out file name
(void)toplevel;
// TODO: Fix nsis to force out file name
std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
if ( nsisInFileName.size() == 0 )
{
......@@ -74,7 +73,7 @@ int cmCPackNSISGenerator::CompressFiles(const char* outFileName,
std::vector<std::string>::const_iterator it;
for ( it = files.begin(); it != files.end(); ++ it )
{
std::string fileN = cmSystemTools::RelativePath(toplevel,
std::string fileN = cmSystemTools::RelativePath(toplevel.c_str(),
it->c_str());
if (!this->Components.empty())
{
......@@ -88,13 +87,13 @@ int cmCPackNSISGenerator::CompressFiles(const char* outFileName,
<< str.str().c_str() << std::endl);
this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
std::vector<std::string> dirs;
this->GetListOfSubdirectories(toplevel, dirs);
this->GetListOfSubdirectories(toplevel.c_str(), dirs);
std::vector<std::string>::const_iterator sit;
cmOStringStream dstr;
for ( sit = dirs.begin(); sit != dirs.end(); ++ sit )
{
std::string componentName;
std::string fileN = cmSystemTools::RelativePath(toplevel, sit->c_str());
std::string fileN = cmSystemTools::RelativePath(toplevel.c_str(), sit->c_str());
if ( fileN.empty() )
{
continue;
......
......@@ -37,8 +37,7 @@ protected:
virtual int InitializeInternal();
void CreateMenuLinks( cmOStringStream& str,
cmOStringStream& deleteStr);
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
virtual const char* GetOutputExtension() { return ".exe"; }
virtual const char* GetOutputPostfix() { return "win32"; }
......
......@@ -33,12 +33,10 @@ cmCPackOSXX11Generator::~cmCPackOSXX11Generator()
}
//----------------------------------------------------------------------
int cmCPackOSXX11Generator::CompressFiles(const char* outFileName,
const char* toplevel,
const std::vector<std::string>& files)
int cmCPackOSXX11Generator::PackageFiles()
{
(void) files; // TODO: Fix api to not need files.
(void) toplevel; // TODO: Use toplevel
// TODO: Use toplevel ?
// It is used! Is this an obsolete comment?
const char* cpackPackageExecutables
= this->GetOption("CPACK_PACKAGE_EXECUTABLES");
......@@ -144,7 +142,7 @@ int cmCPackOSXX11Generator::CompressFiles(const char* outFileName,
dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
<< "\" create -ov -format UDZO -srcfolder \""
<< diskImageDirectory.c_str()
<< "\" \"" << outFileName << "\"";
<< "\" \"" << packageFileNames[0] << "\"";
int retVal = 1;
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Compress disk image using command: "
......
......@@ -33,8 +33,7 @@ public:
protected:
virtual int InitializeInternal();
int CompressFiles(const char* outFileName, const char* toplevel,
const std::vector<std::string>& files);
int PackageFiles();
virtual const char* GetPackagingInstallPrefix();
virtual const char* GetOutputExtension() { return ".dmg"; }
......
......@@ -59,12 +59,10 @@ int cmCPackPackageMakerGenerator::CopyInstallScript(const char* resdir,
}
//----------------------------------------------------------------------
int cmCPackPackageMakerGenerator::CompressFiles(const char* outFileName,
const char* toplevel,
const std::vector<std::string>& files)
int cmCPackPackageMakerGenerator::PackageFiles()
{
(void) files; // TODO: Fix api to not need files.
(void) toplevel; // TODO: Use toplevel
// TODO: Use toplevel
// It is used! Is this an obsolete comment?
std::string resDir; // Where this package's resources will go.