summaryrefslogtreecommitdiffstats
path: root/Source/CPack
diff options
context:
space:
mode:
authorDeniz Bahadir <deniz@code.bahadir.email>2024-05-01 17:20:32 (GMT)
committerDeniz Bahadir <deniz@code.bahadir.email>2024-05-01 17:20:32 (GMT)
commita1af593291efecb5204eb7aa745468dc2a1bf1a7 (patch)
tree432dce8ae55ac182d1541919f3835c59aa68b9ed /Source/CPack
parent9e67ad47a99b549ee02bd48ad2d1ae438f9f3181 (diff)
downloadCMake-a1af593291efecb5204eb7aa745468dc2a1bf1a7.zip
CMake-a1af593291efecb5204eb7aa745468dc2a1bf1a7.tar.gz
CMake-a1af593291efecb5204eb7aa745468dc2a1bf1a7.tar.bz2
CPack: Support arbitrary component name when packaging
CPack no longer blindly tries to create temporary packaging (sub)directories that contain the verbatim name of a component, which might contain characters that are not supported on the platform / filesystem. Instead, if the component's name contains a (possibly) problematic character its MD5 hash will be used for that temporary packaging (sub)directory. Likewise, if the component's name resembles a reserved device name (e.g. "COM1" on Windows) then the temporary packaging (sub)directory will get this name prefixed with an underscore. Similar, if it ends in a dot (on Windows) then the temporary packaging (sub)directory will get this name suffixed with an underscore. Fixes: #23612
Diffstat (limited to 'Source/CPack')
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx18
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.h2
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx9
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx18
-rw-r--r--Source/CPack/cmCPackDebGenerator.h2
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.h2
-rw-r--r--Source/CPack/cmCPackGenerator.cxx56
-rw-r--r--Source/CPack/cmCPackGenerator.h22
-rw-r--r--Source/CPack/cmCPackRPMGenerator.cxx48
-rw-r--r--Source/CPack/cmCPackRPMGenerator.h4
11 files changed, 175 insertions, 28 deletions
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index b3e5fe4..7c82668 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -461,7 +461,7 @@ int cmCPackIFWGenerator::InitializeInternal()
return this->Superclass::InitializeInternal();
}
-std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
+std::string cmCPackIFWGenerator::GetComponentInstallSuffix(
const std::string& componentName)
{
const std::string prefix = "packages/";
@@ -475,6 +475,22 @@ std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
this->GetComponentPackageName(&this->Components[componentName]) + suffix;
}
+std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ const std::string prefix = "packages/";
+ const std::string suffix = "/data";
+
+ if (this->componentPackageMethod == this->ONE_PACKAGE) {
+ return cmStrCat(prefix, this->GetRootPackageName(), suffix);
+ }
+
+ return prefix +
+ this->GetSanitizedDirOrFileName(
+ this->GetComponentPackageName(&this->Components[componentName])) +
+ suffix;
+}
+
cmCPackComponent* cmCPackIFWGenerator::GetComponent(
const std::string& projectName, const std::string& componentName)
{
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.h b/Source/CPack/IFW/cmCPackIFWGenerator.h
index 86b4993..e125be0 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.h
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.h
@@ -67,6 +67,8 @@ protected:
*/
const char* GetOutputExtension() override;
+ std::string GetComponentInstallSuffix(
+ const std::string& componentName) override;
std::string GetComponentInstallDirNameSuffix(
const std::string& componentName) override;
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index b7b6785..8bd3aa0 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -234,7 +234,7 @@ int cmCPackArchiveGenerator::addOneComponentToArchive(
" - packaging component: " << component->Name << std::endl);
// Add the files of this component to the archive
std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
- localToplevel += "/" + component->Name;
+ localToplevel += "/" + this->GetSanitizedDirOrFileName(component->Name);
// Change to local toplevel
cmWorkingDirectory workdir(localToplevel);
if (workdir.Failed()) {
@@ -357,11 +357,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
<< comp.second.Name
<< "> does not belong to any group, package it separately."
<< std::endl);
- std::string localToplevel(
- this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
std::string packageFileName = std::string(this->toplevel);
-
- localToplevel += "/" + comp.first;
packageFileName +=
"/" + this->GetArchiveComponentFileName(comp.first, false);
@@ -379,10 +375,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
// We build 1 package per component
else {
for (auto& comp : this->Components) {
- std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
std::string packageFileName = std::string(this->toplevel);
-
- localToplevel += "/" + comp.first;
packageFileName +=
"/" + this->GetArchiveComponentFileName(comp.first, false);
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 7693891..31191a9 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -536,6 +536,11 @@ int cmCPackDebGenerator::InitializeInternal()
int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
std::string const& packageName)
{
+ // Determine the sanitized packaging directory-name that can be used on the
+ // file-system.
+ std::string sanitizedPkgDirName =
+ this->GetSanitizedDirOrFileName(packageName);
+
// Begin the archive for this pack
std::string localToplevel(initialTopLevel);
std::string packageFileName(
@@ -543,7 +548,7 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
std::string outputFileName(*this->GetOption("CPACK_PACKAGE_FILE_NAME") +
"-" + packageName + this->GetOutputExtension());
- localToplevel += "/" + packageName;
+ localToplevel += "/" + sanitizedPkgDirName;
/* replace the TEMP DIRECTORY with the component one */
this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
packageFileName += "/" + outputFileName;
@@ -554,7 +559,7 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
// Tell CPackDeb.cmake the name of the component GROUP.
this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName);
// Tell CPackDeb.cmake the path where the component is.
- std::string component_path = cmStrCat('/', packageName);
+ std::string component_path = cmStrCat('/', sanitizedPkgDirName);
this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH", component_path);
if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
@@ -894,7 +899,7 @@ bool cmCPackDebGenerator::SupportsComponentInstallation() const
return this->IsOn("CPACK_DEB_COMPONENT_INSTALL");
}
-std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
+std::string cmCPackDebGenerator::GetComponentInstallSuffix(
const std::string& componentName)
{
if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
@@ -913,3 +918,10 @@ std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
}
return componentName;
}
+
+std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return this->GetSanitizedDirOrFileName(
+ this->GetComponentInstallSuffix(componentName));
+}
diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h
index 11561a4..2a8c194 100644
--- a/Source/CPack/cmCPackDebGenerator.h
+++ b/Source/CPack/cmCPackDebGenerator.h
@@ -59,6 +59,8 @@ protected:
int PackageFiles() override;
const char* GetOutputExtension() override { return ".deb"; }
bool SupportsComponentInstallation() const override;
+ std::string GetComponentInstallSuffix(
+ const std::string& componentName) override;
std::string GetComponentInstallDirNameSuffix(
const std::string& componentName) override;
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index b4cada3..4c518ac 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -182,13 +182,14 @@ int cmCPackDragNDropGenerator::PackageFiles()
}
// component install
- std::vector<std::string> package_files;
+ std::vector<std::pair<std::string, std::string>> package_files;
std::map<std::string, cmCPackComponent>::iterator compIt;
for (compIt = this->Components.begin(); compIt != this->Components.end();
++compIt) {
- std::string name = GetComponentInstallDirNameSuffix(compIt->first);
- package_files.push_back(name);
+ std::string dirName = GetComponentInstallDirNameSuffix(compIt->first);
+ std::string fileName = GetComponentInstallSuffix(compIt->first);
+ package_files.emplace_back(fileName, dirName);
}
std::sort(package_files.begin(), package_files.end());
package_files.erase(std::unique(package_files.begin(), package_files.end()),
@@ -198,15 +199,15 @@ int cmCPackDragNDropGenerator::PackageFiles()
packageFileNames.clear();
for (auto const& package_file : package_files) {
std::string full_package_name = cmStrCat(toplevel, '/');
- if (package_file == "ALL_IN_ONE"_s) {
+ if (package_file.first == "ALL_IN_ONE"_s) {
full_package_name += this->GetOption("CPACK_PACKAGE_FILE_NAME");
} else {
- full_package_name += package_file;
+ full_package_name += package_file.first;
}
full_package_name += GetOutputExtension();
packageFileNames.push_back(full_package_name);
- std::string src_dir = cmStrCat(toplevel, '/', package_file);
+ std::string src_dir = cmStrCat(toplevel, '/', package_file.second);
if (0 == this->CreateDMG(src_dir, full_package_name)) {
return 0;
@@ -707,7 +708,7 @@ bool cmCPackDragNDropGenerator::SupportsComponentInstallation() const
return true;
}
-std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
+std::string cmCPackDragNDropGenerator::GetComponentInstallSuffix(
const std::string& componentName)
{
// we want to group components together that go in the same dmg package
@@ -747,6 +748,13 @@ std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
return GetComponentPackageFileName(package_file_name, componentName, false);
}
+std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return this->GetSanitizedDirOrFileName(
+ this->GetComponentInstallSuffix(componentName));
+}
+
void cmCPackDragNDropGenerator::WriteRezXML(std::string const& file,
RezDoc const& rez)
{
diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h
index 6089ae5..249f73e 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.h
+++ b/Source/CPack/cmCPackDragNDropGenerator.h
@@ -35,6 +35,8 @@ protected:
bool CreateEmptyFile(std::ostringstream& target, size_t size);
bool RunCommand(std::string const& command, std::string* output = nullptr);
+ std::string GetComponentInstallSuffix(
+ const std::string& componentName) override;
std::string GetComponentInstallDirNameSuffix(
const std::string& componentName) override;
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 4a5580c..03b8766 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -761,6 +761,7 @@ int cmCPackGenerator::InstallCMakeProject(
// instead of the default
// one install directory for each component.
tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component);
+
if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
tempInstallDirectory += "/";
tempInstallDirectory += *this->GetOption("CPACK_PACKAGE_FILE_NAME");
@@ -965,7 +966,7 @@ int cmCPackGenerator::InstallCMakeProject(
if (componentInstall) {
std::string absoluteDestFileComponent =
std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
- this->GetComponentInstallDirNameSuffix(component);
+ this->GetComponentInstallSuffix(component);
if (nullptr != this->GetOption(absoluteDestFileComponent)) {
std::string absoluteDestFilesListComponent =
cmStrCat(this->GetOption(absoluteDestFileComponent), ';', *d);
@@ -1544,11 +1545,62 @@ int cmCPackGenerator::PrepareGroupingKind()
return 1;
}
-std::string cmCPackGenerator::GetComponentInstallDirNameSuffix(
+std::string cmCPackGenerator::GetSanitizedDirOrFileName(
+ const std::string& name, bool isFullName) const
+{
+ if (isFullName) {
+#ifdef _WIN32
+ // Given name matches a reserved name (on Windows)?
+ // Then return it prepended with an underscore.
+ cmsys::RegularExpression reserved_pattern("^("
+ "[Cc][Oo][Nn]|"
+ "[Pp][Rr][Nn]|"
+ "[Aa][Uu][Xx]|"
+ "[Nn][Uu][Ll]|"
+ "[Cc][Oo][Mm][1-9]|"
+ "[Ll][Pp][Tt][1-9]"
+ ")([.].+)?");
+ if (reserved_pattern.find(name)) {
+ return "_" + name;
+ }
+ // Given name ends in a dot (on Windows)?
+ // Then return it appended with an underscore.
+ if (name.back() == '.') {
+ return name + '_';
+ }
+#endif
+ }
+
+#ifndef _WIN32
+ constexpr const char* prohibited_chars = "<>\"/\\|?*`";
+#else
+ // Note: Windows also excludes the colon.
+ constexpr const char* prohibited_chars = "<>\"/\\|?*`:";
+#endif
+ // Given name contains non-supported character?
+ // Then return its MD5 hash.
+ if (name.find_first_of(prohibited_chars) != std::string::npos) {
+ cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
+ return hasher.HashString(name);
+ }
+
+ // Otherwise return unmodified.
+ return name;
+}
+
+std::string cmCPackGenerator::GetComponentInstallSuffix(
const std::string& componentName)
{
return componentName;
}
+
+std::string cmCPackGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return this->GetSanitizedDirOrFileName(
+ this->GetComponentInstallSuffix(componentName));
+}
+
std::string cmCPackGenerator::GetComponentPackageFileName(
const std::string& initialPackageFileName,
const std::string& groupOrComponentName, bool isGroupName)
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index c9af776..980ab8f 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -145,6 +145,18 @@ protected:
virtual int PrepareGroupingKind();
/**
+ * Ensures that the given name only contains characters that can cleanly be
+ * used as directory or file name and returns this sanitized name. Possibly,
+ * this name might be replaced by its hash.
+ * @param[in] name the name for a directory or file that shall be sanitized.
+ * @param[in] isFullName true if the result is used as the full name for a
+ * directory or file. (Defaults to true.)
+ * @return the sanitized name.
+ */
+ virtual std::string GetSanitizedDirOrFileName(const std::string& name,
+ bool isFullName = true) const;
+
+ /**
* Some CPack generators may prefer to have
* CPack install all components belonging to the same
* [component] group to be install in the same directory.
@@ -154,6 +166,16 @@ protected:
* @return the name suffix the generator wants for the specified component
* default is "componentName"
*/
+ virtual std::string GetComponentInstallSuffix(
+ const std::string& componentName);
+
+ /**
+ * The value that GetComponentInstallSuffix returns, but sanitized.
+ * @param[in] componentName the name of the component to be installed
+ * @return the name suffix the generator wants for the specified component
+ * (but sanitized, so that it can be used on the file-system).
+ * default is "componentName".
+ */
virtual std::string GetComponentInstallDirNameSuffix(
const std::string& componentName);
diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx
index 3d4d05e..8dfb159 100644
--- a/Source/CPack/cmCPackRPMGenerator.cxx
+++ b/Source/CPack/cmCPackRPMGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmCPackComponentGroup.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
+#include "cmCryptoHash.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
@@ -62,7 +63,15 @@ void cmCPackRPMGenerator::AddGeneratedPackageNames()
int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
std::string const& packageName)
{
- int retval = 1;
+ // Determine the sanitized package name that can be used in file-names on
+ // the file-system.
+ std::string sanitizedPkgNameSuffix =
+ this->GetSanitizedDirOrFileName(packageName, false);
+ // Determine the sanitized packaging directory-name that can be used on the
+ // file-system.
+ std::string sanitizedPkgDirName =
+ this->GetSanitizedDirOrFileName(packageName);
+
// Begin the archive for this pack
std::string localToplevel(initialToplevel);
std::string packageFileName(
@@ -72,7 +81,7 @@ int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
this->GetOption("CPACK_PACKAGE_FILE_NAME"), packageName, true) +
this->GetOutputExtension());
- localToplevel += "/" + packageName;
+ localToplevel += "/" + sanitizedPkgDirName;
/* replace the TEMP DIRECTORY with the component one */
this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel);
packageFileName += "/" + outputFileName;
@@ -82,16 +91,34 @@ int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", packageFileName);
// Tell CPackRPM.cmake the name of the component NAME.
this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName);
+ // Tell CPackRPM.cmake the suffix for the component NAME.
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_NAME",
+ sanitizedPkgNameSuffix);
// Tell CPackRPM.cmake the path where the component is.
- std::string component_path = cmStrCat('/', packageName);
+ std::string component_path = cmStrCat('/', sanitizedPkgDirName);
this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH", component_path);
if (!this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while execution CPackRPM.cmake" << std::endl);
- retval = 0;
+ return 0;
}
- return retval;
+ return 1;
+}
+
+std::string cmCPackRPMGenerator::GetSanitizedDirOrFileName(
+ const std::string& name, bool isFullName) const
+{
+ auto sanitizedName =
+ this->cmCPackGenerator::GetSanitizedDirOrFileName(name, isFullName);
+ if (sanitizedName == name && !isFullName) {
+ // Make sure to also sanitize if name contains a colon (':').
+ if (name.find_first_of(':') != std::string::npos) {
+ cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
+ return hasher.HashString(name);
+ }
+ }
+ return sanitizedName;
}
int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
@@ -417,7 +444,7 @@ bool cmCPackRPMGenerator::SupportsComponentInstallation() const
return this->IsOn("CPACK_RPM_COMPONENT_INSTALL");
}
-std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
+std::string cmCPackRPMGenerator::GetComponentInstallSuffix(
const std::string& componentName)
{
if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
@@ -432,7 +459,14 @@ std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
std::string groupVar =
"CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
if (nullptr != this->GetOption(groupVar)) {
- return std::string(this->GetOption(groupVar));
+ return *this->GetOption(groupVar);
}
return componentName;
}
+
+std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ return this->GetSanitizedDirOrFileName(
+ this->GetComponentInstallSuffix(componentName));
+}
diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h
index 886afb1..0e23503 100644
--- a/Source/CPack/cmCPackRPMGenerator.h
+++ b/Source/CPack/cmCPackRPMGenerator.h
@@ -61,7 +61,11 @@ protected:
*/
int PackageComponentsAllInOne(const std::string& compInstDirName);
const char* GetOutputExtension() override { return ".rpm"; }
+ std::string GetSanitizedDirOrFileName(const std::string& name,
+ bool isFullName = true) const override;
bool SupportsComponentInstallation() const override;
+ std::string GetComponentInstallSuffix(
+ const std::string& componentName) override;
std::string GetComponentInstallDirNameSuffix(
const std::string& componentName) override;