Files
CMake/Source/CPack/cmCPackDebGenerator.cxx
T
Alexey Rogachevskiy 9028195a22 CPackDeb: sort package files before generating deb file
This should make the order in which the files are added to md5sums
and archives is stable, thus making package files more reproducible.

Fixes: #22361
2021-06-30 08:47:59 -04:00

925 lines
33 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCPackDebGenerator.h"
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <map>
#include <ostream>
#include <set>
#include <utility>
#include "cmsys/Glob.hxx"
#include "cm_sys_stat.h"
#include "cmArchiveWrite.h"
#include "cmCPackComponentGroup.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
#include "cmCryptoHash.h"
#include "cmGeneratedFileStream.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
namespace {
class DebGenerator
{
public:
DebGenerator(cmCPackLog* logger, std::string outputName, std::string workDir,
std::string topLevelDir, std::string temporaryDir,
const char* debianCompressionType, const char* numThreads,
const char* debianArchiveType,
std::map<std::string, std::string> controlValues,
bool genShLibs, std::string shLibsFilename, bool genPostInst,
std::string postInst, bool genPostRm, std::string postRm,
const char* controlExtra, bool permissionStrctPolicy,
std::vector<std::string> packageFiles);
bool generate() const;
private:
void generateDebianBinaryFile() const;
void generateControlFile() const;
bool generateDataTar() const;
std::string generateMD5File() const;
bool generateControlTar(std::string const& md5Filename) const;
bool generateDeb() const;
cmCPackLog* Logger;
const std::string OutputName;
const std::string WorkDir;
std::string CompressionSuffix;
const std::string TopLevelDir;
const std::string TemporaryDir;
const char* DebianArchiveType;
int NumThreads;
const std::map<std::string, std::string> ControlValues;
const bool GenShLibs;
const std::string ShLibsFilename;
const bool GenPostInst;
const std::string PostInst;
const bool GenPostRm;
const std::string PostRm;
const char* ControlExtra;
const bool PermissionStrictPolicy;
const std::vector<std::string> PackageFiles;
cmArchiveWrite::Compress TarCompressionType;
};
DebGenerator::DebGenerator(
cmCPackLog* logger, std::string outputName, std::string workDir,
std::string topLevelDir, std::string temporaryDir,
const char* debianCompressionType, const char* numThreads,
const char* debianArchiveType,
std::map<std::string, std::string> controlValues, bool genShLibs,
std::string shLibsFilename, bool genPostInst, std::string postInst,
bool genPostRm, std::string postRm, const char* controlExtra,
bool permissionStrictPolicy, std::vector<std::string> packageFiles)
: Logger(logger)
, OutputName(std::move(outputName))
, WorkDir(std::move(workDir))
, TopLevelDir(std::move(topLevelDir))
, TemporaryDir(std::move(temporaryDir))
, DebianArchiveType(debianArchiveType ? debianArchiveType : "gnutar")
, ControlValues(std::move(controlValues))
, GenShLibs(genShLibs)
, ShLibsFilename(std::move(shLibsFilename))
, GenPostInst(genPostInst)
, PostInst(std::move(postInst))
, GenPostRm(genPostRm)
, PostRm(std::move(postRm))
, ControlExtra(controlExtra)
, PermissionStrictPolicy(permissionStrictPolicy)
, PackageFiles(std::move(packageFiles))
{
if (!debianCompressionType) {
debianCompressionType = "gzip";
}
if (!strcmp(debianCompressionType, "lzma")) {
this->CompressionSuffix = ".lzma";
this->TarCompressionType = cmArchiveWrite::CompressLZMA;
} else if (!strcmp(debianCompressionType, "xz")) {
this->CompressionSuffix = ".xz";
this->TarCompressionType = cmArchiveWrite::CompressXZ;
} else if (!strcmp(debianCompressionType, "bzip2")) {
this->CompressionSuffix = ".bz2";
this->TarCompressionType = cmArchiveWrite::CompressBZip2;
} else if (!strcmp(debianCompressionType, "gzip")) {
this->CompressionSuffix = ".gz";
this->TarCompressionType = cmArchiveWrite::CompressGZip;
} else if (!strcmp(debianCompressionType, "none")) {
this->CompressionSuffix.clear();
this->TarCompressionType = cmArchiveWrite::CompressNone;
} else {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error unrecognized compression type: "
<< debianCompressionType << std::endl);
}
if (numThreads == nullptr) {
numThreads = "1";
}
char* endptr;
this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10));
if (numThreads != endptr && *endptr != '\0') {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Unrecognized number of threads: " << numThreads
<< std::endl);
}
}
bool DebGenerator::generate() const
{
this->generateDebianBinaryFile();
this->generateControlFile();
if (!this->generateDataTar()) {
return false;
}
std::string md5Filename = this->generateMD5File();
if (!this->generateControlTar(md5Filename)) {
return false;
}
return this->generateDeb();
}
void DebGenerator::generateDebianBinaryFile() const
{
// debian-binary file
const std::string dbfilename = this->WorkDir + "/debian-binary";
cmGeneratedFileStream out;
out.Open(dbfilename, false, true);
out << "2.0\n"; // required for valid debian package
}
void DebGenerator::generateControlFile() const
{
std::string ctlfilename = this->WorkDir + "/control";
cmGeneratedFileStream out;
out.Open(ctlfilename, false, true);
for (auto const& kv : this->ControlValues) {
out << kv.first << ": " << kv.second << "\n";
}
unsigned long totalSize = 0;
{
for (std::string const& file : this->PackageFiles) {
totalSize += cmSystemTools::FileLength(file);
}
}
out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n\n";
}
bool DebGenerator::generateDataTar() const
{
std::string filename_data_tar =
this->WorkDir + "/data.tar" + this->CompressionSuffix;
cmGeneratedFileStream fileStream_data_tar;
fileStream_data_tar.Open(filename_data_tar, false, true);
if (!fileStream_data_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \""
<< filename_data_tar << "\" for writing" << std::endl);
return false;
}
cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
this->DebianArchiveType, 0, this->NumThreads);
data_tar.Open();
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
data_tar.SetUIDAndGID(0u, 0u);
data_tar.SetUNAMEAndGNAME("root", "root");
// 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 = this->WorkDir.length();
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"WDIR: \"" << this->WorkDir
<< "\", length = " << topLevelLength << std::endl);
std::set<std::string> orderedFiles;
// we have to reconstruct the parent folders as well
for (std::string currentPath : this->PackageFiles) {
while (currentPath != this->WorkDir) {
// the last one IS WorkDir, but we do not want this one:
// XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
// should not add XXX/application
orderedFiles.insert(currentPath);
currentPath = cmSystemTools::CollapseFullPath("..", currentPath);
}
}
for (std::string const& file : orderedFiles) {
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"FILEIT: \"" << file << "\"" << std::endl);
std::string::size_type slashPos = file.find('/', topLevelLength + 1);
std::string relativeDir =
file.substr(topLevelLength, slashPos - topLevelLength);
cmCPackLogger(cmCPackLog::LOG_DEBUG,
"RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
#ifdef WIN32
std::string mode_t_adt_filename = file + ":cmake_mode_t";
cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
mode_t permissions = 0;
if (permissionStream) {
permissionStream >> std::oct >> permissions;
}
if (permissions != 0) {
data_tar.SetPermissions(permissions);
} else if (cmSystemTools::FileIsDirectory(file)) {
data_tar.SetPermissions(0755);
} else {
data_tar.ClearPermissions();
}
#endif
// do not recurse because the loop will do it
if (!data_tar.Add(file, topLevelLength, ".", false)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem adding file to tar:"
<< std::endl
<< "#top level directory: " << this->WorkDir << std::endl
<< "#file: " << file << std::endl
<< "#error:" << data_tar.GetError() << std::endl);
return false;
}
}
return true;
}
std::string DebGenerator::generateMD5File() const
{
std::string md5filename = this->WorkDir + "/md5sums";
cmGeneratedFileStream out;
out.Open(md5filename, false, true);
std::string topLevelWithTrailingSlash = cmStrCat(this->TemporaryDir, '/');
for (std::string const& file : this->PackageFiles) {
// hash only regular files
if (cmSystemTools::FileIsDirectory(file) ||
cmSystemTools::FileIsSymlink(file)) {
continue;
}
std::string output =
cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
if (output.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem computing the md5 of " << file << std::endl);
}
output += " " + file + "\n";
// debian md5sums entries are like this:
// 014f3604694729f3bf19263bac599765 usr/bin/ccmake
// thus strip the full path (with the trailing slash)
cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
"");
out << output;
}
// each line contains a eol.
// Do not end the md5sum file with yet another (invalid)
return md5filename;
}
bool DebGenerator::generateControlTar(std::string const& md5Filename) const
{
std::string filename_control_tar = this->WorkDir + "/control.tar.gz";
cmGeneratedFileStream fileStream_control_tar;
fileStream_control_tar.Open(filename_control_tar, false, true);
if (!fileStream_control_tar) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error opening the file \""
<< filename_control_tar << "\" for writing" << std::endl);
return false;
}
cmArchiveWrite control_tar(fileStream_control_tar,
cmArchiveWrite::CompressGZip,
this->DebianArchiveType);
control_tar.Open();
// sets permissions and uid/gid for the files
control_tar.SetUIDAndGID(0u, 0u);
control_tar.SetUNAMEAndGNAME("root", "root");
/* permissions are set according to
https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
and
https://lintian.debian.org/tags/control-file-has-bad-permissions.html
*/
const mode_t permission644 = 0644;
const mode_t permissionExecute = 0111;
const mode_t permission755 = permission644 | permissionExecute;
// for md5sum and control (that we have generated here), we use 644
// (RW-R--R--)
// so that deb lintian doesn't warn about it
control_tar.SetPermissions(permission644);
// adds control and md5sums
if (!control_tar.Add(md5Filename, this->WorkDir.length(), ".") ||
!control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(),
".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << this->WorkDir << std::endl
<< "#file: \"control\" or \"md5sums\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
// adds generated shlibs file
if (this->GenShLibs) {
if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << this->WorkDir << std::endl
<< "#file: \"shlibs\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
}
// adds LDCONFIG related files
if (this->GenPostInst) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << this->WorkDir << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
control_tar.SetPermissions(permission644);
}
if (this->GenPostRm) {
control_tar.SetPermissions(permission755);
if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error adding file to tar:"
<< std::endl
<< "#top level directory: " << this->WorkDir << std::endl
<< "#file: \"postinst\"" << std::endl
<< "#error:" << control_tar.GetError() << std::endl);
return false;
}
control_tar.SetPermissions(permission644);
}
// for the other files, we use
// -either the original permission on the files
// -either a permission strictly defined by the Debian policies
if (this->ControlExtra) {
// permissions are now controlled by the original file permissions
static const char* strictFiles[] = { "config", "postinst", "postrm",
"preinst", "prerm" };
std::set<std::string> setStrictFiles(
strictFiles, strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
// default
control_tar.ClearPermissions();
std::vector<std::string> controlExtraList =
cmExpandedList(this->ControlExtra);
for (std::string const& i : controlExtraList) {
std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
std::string localcopy = this->WorkDir + "/" + filenamename;
if (this->PermissionStrictPolicy) {
control_tar.SetPermissions(
setStrictFiles.count(filenamename) ? permission755 : permission644);
}
// if we can copy the file, it means it does exist, let's add it:
if (!cmsys::SystemTools::FileExists(i)) {
cmCPackLogger(cmCPackLog::LOG_WARNING,
"Adding file to tar:" << std::endl
<< "#top level directory: "
<< this->WorkDir << std::endl
<< "#missing file: " << i
<< std::endl);
}
if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
control_tar.Add(localcopy, this->WorkDir.length(), ".");
}
}
}
return true;
}
bool DebGenerator::generateDeb() const
{
// ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
// A debian package .deb is simply an 'ar' archive. The only subtle
// difference is that debian uses the BSD ar style archive whereas most
// Linux distro have a GNU ar.
// See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
std::string const outputPath = this->TopLevelDir + "/" + this->OutputName;
std::string const tlDir = this->WorkDir + "/";
cmGeneratedFileStream debStream;
debStream.Open(outputPath, false, true);
cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
deb.Open();
// uid/gid should be the one of the root user, and this root user has
// always uid/gid equal to 0.
deb.SetUIDAndGID(0u, 0u);
deb.SetUNAMEAndGNAME("root", "root");
if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
!deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
!deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error creating debian package:"
<< std::endl
<< "#top level directory: " << this->TopLevelDir
<< std::endl
<< "#file: " << this->OutputName << std::endl
<< "#error:" << deb.GetError() << std::endl);
return false;
}
return true;
}
} // end anonymous namespace
cmCPackDebGenerator::cmCPackDebGenerator() = default;
cmCPackDebGenerator::~cmCPackDebGenerator() = default;
int cmCPackDebGenerator::InitializeInternal()
{
this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
if (cmIsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
this->SetOption("CPACK_SET_DESTDIR", "I_ON");
}
return this->Superclass::InitializeInternal();
}
int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
std::string const& packageName)
{
int retval = 1;
// Begin the archive for this pack
std::string localToplevel(initialTopLevel);
std::string packageFileName(
cmSystemTools::GetParentDirectory(this->toplevel));
std::string outputFileName(
std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
packageName + this->GetOutputExtension());
localToplevel += "/" + packageName;
/* replace the TEMP DIRECTORY with the component one */
this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
packageFileName += "/" + outputFileName;
/* replace proposed CPACK_OUTPUT_FILE_NAME */
this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
/* replace the TEMPORARY package file name */
this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
packageFileName.c_str());
// Tell CPackDeb.cmake the name of the component GROUP.
this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName.c_str());
// Tell CPackDeb.cmake the path where the component is.
std::string component_path = cmStrCat('/', packageName);
this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
component_path.c_str());
if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while execution CPackDeb.cmake" << std::endl);
retval = 0;
return retval;
}
{ // Isolate globbing of binaries vs. dbgsyms
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_WDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
gl.SetRecurseThroughSymlinks(false);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
}
this->packageFiles = gl.GetFiles();
// Sort files so that they have a reproducible order
std::sort(this->packageFiles.begin(), this->packageFiles.end());
}
int res = this->createDeb();
if (res != 1) {
retval = 0;
}
// add the generated package to package file names list
packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
this->packageFileNames.push_back(std::move(packageFileName));
if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") &&
this->GetOption("GEN_DBGSYMDIR")) {
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
gl.SetRecurseThroughSymlinks(false);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
}
this->packageFiles = gl.GetFiles();
// Sort files so that they have a reproducible order
std::sort(this->packageFiles.begin(), this->packageFiles.end());
res = this->createDbgsymDDeb();
if (res != 1) {
retval = 0;
}
// add the generated package to package file names list
packageFileName =
cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"));
this->packageFileNames.push_back(std::move(packageFileName));
}
return retval;
}
int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
{
int retval = 1;
/* Reset package file name list it will be populated during the
* component packaging run*/
this->packageFileNames.clear();
std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
// The default behavior is to have one package by component group
// unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
if (!ignoreGroup) {
for (auto const& compG : this->ComponentGroups) {
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Packaging component group: " << compG.first << std::endl);
// Begin the archive for this group
retval &= this->PackageOnePack(initialTopLevel, compG.first);
}
// Handle Orphan components (components not belonging to any groups)
for (auto const& comp : this->Components) {
// Does the component belong to a group?
if (comp.second.Group == nullptr) {
cmCPackLogger(
cmCPackLog::LOG_VERBOSE,
"Component <"
<< comp.second.Name
<< "> does not belong to any group, package it separately."
<< std::endl);
// Begin the archive for this orphan component
retval &= this->PackageOnePack(initialTopLevel, comp.first);
}
}
}
// CPACK_COMPONENTS_IGNORE_GROUPS is set
// We build 1 package per component
else {
for (auto const& comp : this->Components) {
retval &= this->PackageOnePack(initialTopLevel, comp.first);
}
}
return retval;
}
//----------------------------------------------------------------------
int cmCPackDebGenerator::PackageComponentsAllInOne(
const std::string& compInstDirName)
{
int retval = 1;
/* Reset package file name list it will be populated during the
* component packaging run*/
this->packageFileNames.clear();
std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Packaging all groups in one package..."
"(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
<< std::endl);
// The ALL GROUPS in ONE package case
std::string localToplevel(initialTopLevel);
std::string packageFileName(
cmSystemTools::GetParentDirectory(this->toplevel));
std::string outputFileName(
std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
this->GetOutputExtension());
// all GROUP in one vs all COMPONENT in one
// if must be here otherwise non component paths have a trailing / while
// components don't
if (!compInstDirName.empty()) {
localToplevel += "/" + compInstDirName;
}
/* replace the TEMP DIRECTORY with the component one */
this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str());
packageFileName += "/" + outputFileName;
/* replace proposed CPACK_OUTPUT_FILE_NAME */
this->SetOption("CPACK_OUTPUT_FILE_NAME", outputFileName.c_str());
/* replace the TEMPORARY package file name */
this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
packageFileName.c_str());
if (!compInstDirName.empty()) {
// Tell CPackDeb.cmake the path where the component is.
std::string component_path = cmStrCat('/', compInstDirName);
this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
component_path.c_str());
}
if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while execution CPackDeb.cmake" << std::endl);
retval = 0;
return retval;
}
cmsys::Glob gl;
std::string findExpr(this->GetOption("GEN_WDIR"));
findExpr += "/*";
gl.RecurseOn();
gl.SetRecurseListDirs(true);
gl.SetRecurseThroughSymlinks(false);
if (!gl.FindFiles(findExpr)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find any files in the installed directory"
<< std::endl);
return 0;
}
this->packageFiles = gl.GetFiles();
// Sort files so that they have a reproducible order
std::sort(this->packageFiles.begin(), this->packageFiles.end());
int res = this->createDeb();
if (res != 1) {
retval = 0;
}
// add the generated package to package file names list
packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
this->packageFileNames.push_back(std::move(packageFileName));
return retval;
}
int cmCPackDebGenerator::PackageFiles()
{
/* Are we in the component packaging case */
if (this->WantsComponentInstallation()) {
// CASE 1 : COMPONENT ALL-IN-ONE package
// If ALL GROUPS or ALL COMPONENTS in ONE package has been requested
// then the package file is unique and should be open here.
if (this->componentPackageMethod == ONE_PACKAGE) {
return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
}
// CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
// There will be 1 package for each component group
// however one may require to ignore component group and
// in this case you'll get 1 package for each component.
return this->PackageComponents(this->componentPackageMethod ==
ONE_PACKAGE_PER_COMPONENT);
}
// CASE 3 : NON COMPONENT package.
return this->PackageComponentsAllInOne("");
}
int cmCPackDebGenerator::createDeb()
{
std::map<std::string, std::string> controlValues;
// debian policy enforce lower case for package name
controlValues["Package"] = cmsys::SystemTools::LowerCase(
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
controlValues["Version"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
controlValues["Section"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
controlValues["Priority"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
controlValues["Architecture"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
controlValues["Maintainer"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
controlValues["Description"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
const char* debian_pkg_source =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
if (cmNonempty(debian_pkg_source)) {
controlValues["Source"] = debian_pkg_source;
}
const char* debian_pkg_dep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
if (cmNonempty(debian_pkg_dep)) {
controlValues["Depends"] = debian_pkg_dep;
}
const char* debian_pkg_rec =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
if (cmNonempty(debian_pkg_rec)) {
controlValues["Recommends"] = debian_pkg_rec;
}
const char* debian_pkg_sug =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
if (cmNonempty(debian_pkg_sug)) {
controlValues["Suggests"] = debian_pkg_sug;
}
const char* debian_pkg_url =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
if (cmNonempty(debian_pkg_url)) {
controlValues["Homepage"] = debian_pkg_url;
}
const char* debian_pkg_predep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
if (cmNonempty(debian_pkg_predep)) {
controlValues["Pre-Depends"] = debian_pkg_predep;
}
const char* debian_pkg_enhances =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
if (cmNonempty(debian_pkg_enhances)) {
controlValues["Enhances"] = debian_pkg_enhances;
}
const char* debian_pkg_breaks =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
if (cmNonempty(debian_pkg_breaks)) {
controlValues["Breaks"] = debian_pkg_breaks;
}
const char* debian_pkg_conflicts =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
if (cmNonempty(debian_pkg_conflicts)) {
controlValues["Conflicts"] = debian_pkg_conflicts;
}
const char* debian_pkg_provides =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
if (cmNonempty(debian_pkg_provides)) {
controlValues["Provides"] = debian_pkg_provides;
}
const char* debian_pkg_replaces =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
if (cmNonempty(debian_pkg_replaces)) {
controlValues["Replaces"] = debian_pkg_replaces;
}
const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
const std::string shlibsfilename = strGenWDIR + "/shlibs";
const char* debian_pkg_shlibs =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS");
const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") &&
cmNonempty(debian_pkg_shlibs);
if (gen_shibs) {
cmGeneratedFileStream out;
out.Open(shlibsfilename, false, true);
out << debian_pkg_shlibs;
out << '\n';
}
const std::string postinst = strGenWDIR + "/postinst";
const std::string postrm = strGenWDIR + "/postrm";
if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
cmGeneratedFileStream out;
out.Open(postinst, false, true);
out << "#!/bin/sh\n\n"
"set -e\n\n"
"if [ \"$1\" = \"configure\" ]; then\n"
"\tldconfig\n"
"fi\n";
}
if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
cmGeneratedFileStream out;
out.Open(postrm, false, true);
out << "#!/bin/sh\n\n"
"set -e\n\n"
"if [ \"$1\" = \"remove\" ]; then\n"
"\tldconfig\n"
"fi\n";
}
DebGenerator gen(
this->Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
this->GetOption("CPACK_THREADS"),
this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm,
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"),
this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
this->packageFiles);
if (!gen.generate()) {
return 0;
}
return 1;
}
int cmCPackDebGenerator::createDbgsymDDeb()
{
// Packages containing debug symbols follow the same structure as .debs
// but have different metadata and content.
std::map<std::string, std::string> controlValues;
// debian policy enforce lower case for package name
std::string packageNameLower = cmsys::SystemTools::LowerCase(
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
const char* debian_pkg_version =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
controlValues["Package"] = packageNameLower + "-dbgsym";
controlValues["Package-Type"] = "ddeb";
controlValues["Version"] = debian_pkg_version;
controlValues["Auto-Built-Package"] = "debug-symbols";
controlValues["Depends"] = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") +
std::string(" (= ") + debian_pkg_version + ")";
controlValues["Section"] = "debug";
controlValues["Priority"] = "optional";
controlValues["Architecture"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
controlValues["Maintainer"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
controlValues["Description"] =
std::string("debug symbols for ") + packageNameLower;
const char* debian_pkg_source =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
if (cmNonempty(debian_pkg_source)) {
controlValues["Source"] = debian_pkg_source;
}
const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS");
if (cmNonempty(debian_build_ids)) {
controlValues["Build-Ids"] = debian_build_ids;
}
DebGenerator gen(
this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
this->GetOption("GEN_DBGSYMDIR"),
this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
this->GetOption("CPACK_THREADS"),
this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
false, "", false, "", nullptr,
this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
this->packageFiles);
if (!gen.generate()) {
return 0;
}
return 1;
}
bool cmCPackDebGenerator::SupportsComponentInstallation() const
{
return this->IsOn("CPACK_DEB_COMPONENT_INSTALL");
}
std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
const std::string& componentName)
{
if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
return componentName;
}
if (this->componentPackageMethod == ONE_PACKAGE) {
return std::string("ALL_COMPONENTS_IN_ONE");
}
// We have to find the name of the COMPONENT GROUP
// the current COMPONENT belongs to.
std::string groupVar =
"CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
if (nullptr != this->GetOption(groupVar)) {
return std::string(this->GetOption(groupVar));
}
return componentName;
}