We needed directory entries explicitly listed in zip file headers, so I created this patch. It DOES NOT solve the issue with empty directories. It knows what directories to include by analyzing file paths during addition to archive. ===========================================================================================
>From 700075de0d05042a10074ad9e24995c6a9087e1e Mon Sep 17 00:00:00 2001 From: Jakub Zakrzewski <[email protected]> Date: Thu, 19 Jan 2012 17:21:18 +0100 Subject: [PATCH] Added possibility to force inclusion of directory entries in achive files (zip, tgz...) In normal case only files were added to archive file filelist. Due to some legancy requirements it may be necessary to have also apropriate entries for directories theirselves, so instead of having only entry for 'dir/dir2/file.txt' one may want to have three entries: * 'dir/' * 'dir/dir2/' * 'dir/dir2/file.txt' To achieve this simply set variable CPACK_ARCHIVE_INCLUDE_DIRECTORY_ENTRIES to ON. --- Source/CPack/cmCPackArchiveGenerator.cxx | 58 ++++++++++++++++++++++++++++++ Source/CPack/cmCPackComponentGroup.h | 3 ++ Source/CPack/cmCPackGenerator.cxx | 22 +++++++++++ Source/cmArchiveWrite.cxx | 14 +++++++ Source/cmArchiveWrite.h | 11 ++++++ 5 files changed, 108 insertions(+), 0 deletions(-) diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 0ce5b01..803ff64 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -57,6 +57,21 @@ int cmCPackArchiveGenerator::addOneComponentToArchive(cmArchiveWrite& archive, std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); // Change to local toplevel cmSystemTools::ChangeDirectory(localToplevel.c_str()); + std::set<std::string>::const_iterator dirIt; + for (dirIt = component->DirectoryEntries.begin(); dirIt != component->DirectoryEntries.end(); + ++dirIt ) + { + cmCPackLogger(cmCPackLog::LOG_DEBUG,"Adding directory entry: " + << (*dirIt) << std::endl); + archive.AddDirEntry(*dirIt); + if (!archive) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging directory entries: " + << archive.GetError() + << std::endl); + return 0; + } + } std::vector<std::string>::const_iterator fileIt; for (fileIt = component->Files.begin(); fileIt != component->Files.end(); ++fileIt ) @@ -264,6 +279,49 @@ int cmCPackArchiveGenerator::PackageFiles() std::vector<std::string>::const_iterator fileIt; std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); cmSystemTools::ChangeDirectory(toplevel.c_str()); + bool packageDirEntries = this->IsOn("CPACK_ARCHIVE_INCLUDE_DIRECTORY_ENTRIES"); + if(packageDirEntries) + { + + std::set<std::string> directoryEntries; + for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt ) + { + // Get the relative path to the file + std::string localDirName = cmSystemTools::RelativePath(toplevel.c_str(), + fileIt->c_str()); + bool stop = true; + do + { + size_t lastSeparatorPosition = localDirName.find_last_of('/'); + if(lastSeparatorPosition < localDirName.size()) + { + localDirName.resize(lastSeparatorPosition); + stop = !directoryEntries.insert(localDirName).second; + } + else + { + stop = true; + } + } + while (!stop); + } + + std::set<std::string>::const_iterator dirIt; + for (dirIt = directoryEntries.begin(); dirIt != directoryEntries.end(); ++dirIt ) + { + cmCPackLogger(cmCPackLog::LOG_DEBUG,"Adding directory entry: " + << (*dirIt) << std::endl); + archive.AddDirEntry(*dirIt); + if (!archive) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging directory entries: " + << archive.GetError() + << std::endl); + return 0; + } + } + } + for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt ) { // Get the relative path to the file diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h index cebdd6d..c0b71e2 100644 --- a/Source/CPack/cmCPackComponentGroup.h +++ b/Source/CPack/cmCPackComponentGroup.h @@ -89,6 +89,9 @@ public: /// The list of installed directories that are part of this component. std::vector<std::string> Directories; + /// The list of directory entries that are to be put into archive. + std::set<std::string> DirectoryEntries; + /// Get the total installed size of all of the files in this /// component, in bytes. installDir is the directory into which the /// component was installed. diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 083279f..24925c1 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -842,7 +842,10 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( result.begin()); std::vector<std::string>::iterator fit; + std::string localFileName; + std::string localDirName; + bool packageDirEntries = this->IsOn("CPACK_ARCHIVE_INCLUDE_DIRECTORY_ENTRIES"); // Populate the File field of each component for (fit=result.begin();fit!=diff;++fit) { @@ -851,6 +854,25 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( localFileName = localFileName.substr(localFileName.find('/')+1, std::string::npos); + if(packageDirEntries) + { + localDirName = localFileName; + bool stop = true; + do + { + size_t lastSeparatorPosition = localDirName.find_last_of('/'); + if(lastSeparatorPosition < localDirName.size()) + { + localDirName.resize(lastSeparatorPosition); + stop = !Components[installComponent].DirectoryEntries.insert(localDirName).second; + } + else + { + stop = true; + } + } + while (!stop && !localDirName.empty()); + } Components[installComponent].Files.push_back(localFileName); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file <" <<localFileName<<"> to component <" diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index dc6b749..c79f9d5 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -173,6 +173,20 @@ bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix) } //---------------------------------------------------------------------------- +bool cmArchiveWrite::AddDirEntry(std::string path, size_t skip, const char* prefix) +{ + if(this->Okay()) + { + if(!path.empty() && path[path.size()-1] == '/') + { + path.erase(path.size()-1); + } + this->AddFile(path.c_str(), skip, prefix); + } + return this->Okay(); +} + +//---------------------------------------------------------------------------- bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix) { diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index 3e3b2f0..4b2e81c 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -59,6 +59,17 @@ public: */ bool Add(std::string path, size_t skip = 0, const char* prefix = 0); + /** + * Add a directory entry to the archive. This causes the archive to + * store additional information about directories and not only + * abot their content. The "path" must be readable on disk, either + * full path or relative to current working directory. The "skip" + * value indicates how many leading bytes from the input path to + * skip. The remaining part of the input path is appended to the + * "prefix" value to construct the final name in the archive. + */ + bool AddDirEntry(std::string path, size_t skip = 0, const char* prefix = 0); + /** Returns true if there has been no error. */ operator safe_bool() const { return this->Okay()? &cmArchiveWrite::safe_bool_true : 0; } -- 1.7.7 -- Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake
