From 07fa9ac09c69b098af08429eccaf332c15b97f1e Mon Sep 17 00:00:00 2001 From: Andy Cedilnik Date: Mon, 21 Aug 2006 12:37:40 -0400 Subject: ENH: Implement TarCompress generator using compress library --- Source/CMakeLists.txt | 5 +- Source/CPack/cmCPackTarCompressGenerator.cxx | 271 +++++++++++++++++---------- Source/CPack/cmCPackTarCompressGenerator.h | 1 + 3 files changed, 179 insertions(+), 98 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e9221e5..f6770f8 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -19,6 +19,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_ZLIB_INCLUDES} ${CMAKE_EXPAT_INCLUDES} ${CMAKE_TAR_INCLUDES} + ${CMAKE_COMPRESS_INCLUDES} ) # let cmake know it is supposed to use it @@ -217,7 +218,9 @@ ENDIF (WIN32) # create a library used by the command line and the GUI ADD_LIBRARY(CMakeLib ${SRCS}) -TARGET_LINK_LIBRARIES(CMakeLib cmsys ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES} ${CMAKE_TAR_LIBRARIES}) +TARGET_LINK_LIBRARIES(CMakeLib cmsys + ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES} + ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}) # On Apple we need Carbon IF(APPLE) diff --git a/Source/CPack/cmCPackTarCompressGenerator.cxx b/Source/CPack/cmCPackTarCompressGenerator.cxx index b911005..caab168 100644 --- a/Source/CPack/cmCPackTarCompressGenerator.cxx +++ b/Source/CPack/cmCPackTarCompressGenerator.cxx @@ -26,19 +26,25 @@ #include "cmCPackLog.h" #include +#include +#include +#include // auto_ptr +#include +#include -// Includes needed for implementation of RenameFile. This is not in -// system tools because it is not implemented robustly enough to move -// files across directories. -#ifdef _WIN32 -# include -# include -#endif +//---------------------------------------------------------------------- +class cmCPackTarCompressGeneratorForward +{ + public: + static int GenerateHeader(cmCPackTarCompressGenerator* gg, std::ostream* os) + { + return gg->GenerateHeader(os); + } +}; //---------------------------------------------------------------------- cmCPackTarCompressGenerator::cmCPackTarCompressGenerator() { - this->Compress = false; } //---------------------------------------------------------------------- @@ -46,124 +52,195 @@ cmCPackTarCompressGenerator::~cmCPackTarCompressGenerator() { } +static const size_t cmCPackTarCompress_Data_BlockSize = 16384; + //---------------------------------------------------------------------- -int cmCPackTarCompressGenerator::InitializeInternal() +class cmCPackTarCompress_Data { - this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); - std::vector path; - std::string pkgPath = cmSystemTools::FindProgram("compress", path, false); - if ( pkgPath.empty() ) +public: + cmCPackTarCompress_Data(cmCPackTarCompressGenerator* gen) : + OutputStream(0), Generator(gen) {} + std::ostream* OutputStream; + cmCPackTarCompressGenerator* Generator; + cmcompress_stream CMCompressStream; +}; + +//---------------------------------------------------------------------- +extern "C" { + // For cmTar + int cmCPackTarCompress_Data_Open(void *client_data, const char* name, + int oflags, mode_t mode); + ssize_t cmCPackTarCompress_Data_Write(void *client_data, void *buff, + size_t n); + int cmCPackTarCompress_Data_Close(void *client_data); + + // For cmCompress + int cmCPackTarCompress_Compress_Output(void* cdata, const char* data, + int len); +} + + +//---------------------------------------------------------------------- +int cmCPackTarCompress_Data_Open(void *client_data, const char* pathname, + int, mode_t) +{ + cmCPackTarCompress_Data *mydata = (cmCPackTarCompress_Data*)client_data; + + if ( !cmcompress_compress_initialize(&mydata->CMCompressStream) ) { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find Compress" << std::endl); - return 0; + return -1; } - this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str()); - cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Found Compress program: " - << pkgPath.c_str() - << std::endl); - return this->Superclass::InitializeInternal(); + mydata->CMCompressStream.client_data = mydata; + mydata->CMCompressStream.output_stream = cmCPackTarCompress_Compress_Output; + + cmGeneratedFileStream* gf = new cmGeneratedFileStream; + // Open binary + gf->Open(pathname, false, true); + mydata->OutputStream = gf; + if ( !*mydata->OutputStream ) + { + return -1; + } + + if ( !cmcompress_compress_start(&mydata->CMCompressStream) ) + { + return -1; + } + + + if ( !cmCPackTarCompressGeneratorForward::GenerateHeader( + mydata->Generator,gf)) + { + return -1; + } + + return 0; } //---------------------------------------------------------------------- -int cmCPackTarCompressGenerator::CompressFiles(const char* outFileName, - const char* toplevel, const std::vector& files) +ssize_t cmCPackTarCompress_Data_Write(void *client_data, void *buff, size_t n) { - std::string packageDirFileName - = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); - packageDirFileName += ".tar"; - std::string output; - int retVal = -1; - if ( !this->Superclass::CompressFiles(packageDirFileName.c_str(), - toplevel, files) ) + cmCPackTarCompress_Data *mydata = (cmCPackTarCompress_Data*)client_data; + + if ( !cmcompress_compress(&mydata->CMCompressStream, buff, n) ) { return 0; } + return n; +} - cmOStringStream dmgCmd1; - dmgCmd1 << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM") - << "\" \"" << packageDirFileName - << "\""; - retVal = -1; - int res = cmSystemTools::RunSingleCommand(dmgCmd1.str().c_str(), &output, - &retVal, toplevel, this->GeneratorVerbose, 0); - if ( !res || retVal ) +//---------------------------------------------------------------------- +int cmCPackTarCompress_Data_Close(void *client_data) +{ + cmCPackTarCompress_Data *mydata = (cmCPackTarCompress_Data*)client_data; + + if ( !cmcompress_compress_finalize(&mydata->CMCompressStream) ) { - std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); - tmpFile += "/CompressCompress.log"; - cmGeneratedFileStream ofs(tmpFile.c_str()); - ofs << "# Run command: " << dmgCmd1.str().c_str() << std::endl - << "# Output:" << std::endl - << output.c_str() << std::endl; - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running Compress command: " - << dmgCmd1.str().c_str() << std::endl - << "Please check " << tmpFile.c_str() << " for errors" << std::endl); + delete mydata->OutputStream; + return -1; + } + + delete mydata->OutputStream; + mydata->OutputStream = 0; + return (0); +} + +//---------------------------------------------------------------------- +int cmCPackTarCompressGenerator::InitializeInternal() +{ + this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); + return this->Superclass::InitializeInternal(); +} + +//---------------------------------------------------------------------- +int cmCPackTarCompressGenerator::CompressFiles(const char* outFileName, + const char* toplevel, const std::vector& files) +{ + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); + cmCPackTarCompress_Data mydata(this); + TAR *t; + char buf[TAR_MAXPATHLEN]; + char pathname[TAR_MAXPATHLEN]; + + tartype_t compressType = { + (openfunc_t)cmCPackTarCompress_Data_Open, + (closefunc_t)cmCPackTarCompress_Data_Close, + (readfunc_t)0, + (writefunc_t)cmCPackTarCompress_Data_Write, + &mydata + }; + + // Ok, this libtar is not const safe. for now use auto_ptr hack + char* realName = new char[ strlen(outFileName) + 1 ]; + std::auto_ptr realNamePtr(realName); + strcpy(realName, outFileName); + int flags = O_WRONLY | O_CREAT; + if (tar_open(&t, realName, + &compressType, + flags, 0644, + (this->GeneratorVerbose?TAR_VERBOSE:0) + | 0) == -1) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_open(): " + << strerror(errno) << std::endl); return 0; } - std::string compressOutFile = packageDirFileName + ".Z"; - if ( !cmSystemTools::SameFile(compressOutFile.c_str(), outFileName ) ) + std::vector::const_iterator fileIt; + for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt ) { - if ( !this->RenameFile(compressOutFile.c_str(), outFileName) ) + std::string rp = cmSystemTools::RelativePath(toplevel, fileIt->c_str()); + strncpy(pathname, fileIt->c_str(), sizeof(pathname)); + pathname[sizeof(pathname)-1] = 0; + strncpy(buf, rp.c_str(), sizeof(buf)); + buf[sizeof(buf)-1] = 0; + if (tar_append_tree(t, pathname, buf) != 0) { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem renaming: \"" - << compressOutFile.c_str() << "\" to \"" - << outFileName << std::endl); + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem with tar_append_tree(\"" << buf << "\", \"" + << pathname << "\"): " + << strerror(errno) << std::endl); + tar_close(t); return 0; } } + if (tar_append_eof(t) != 0) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_append_eof(): " + << strerror(errno) << std::endl); + tar_close(t); + return 0; + } + if (tar_close(t) != 0) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem with tar_close(): " + << strerror(errno) << std::endl); + return 0; + } return 1; } -//---------------------------------------------------------------------------- -int cmCPackTarCompressGenerator::RenameFile(const char* oldname, - const char* newname) +//---------------------------------------------------------------------- +int cmCPackTarCompress_Compress_Output(void* client_data, + const char* data, int data_length) { -#ifdef _WIN32 - /* On Windows the move functions will not replace existing files. - Check if the destination exists. */ - struct stat newFile; - if(stat(newname, &newFile) == 0) - { - /* The destination exists. We have to replace it carefully. The - MoveFileEx function does what we need but is not available on - Win9x. */ - OSVERSIONINFO osv; - DWORD attrs; - - /* Make sure the destination is not read only. */ - attrs = GetFileAttributes(newname); - if(attrs & FILE_ATTRIBUTE_READONLY) - { - SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY); - } + cmcompress_stream *cstream = static_cast(client_data); + cmCPackTarCompress_Data *mydata + = static_cast(cstream->client_data); + mydata->OutputStream->write(data, data_length); - /* Check the windows version number. */ - osv.dwOSVersionInfoSize = sizeof(osv); - GetVersionEx(&osv); - if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - { - /* This is Win9x. There is no MoveFileEx implementation. We - cannot quite rename the file atomically. Just delete the - destination and then move the file. */ - DeleteFile(newname); - return MoveFile(oldname, newname); - } - else - { - /* This is not Win9x. Use the MoveFileEx implementation. */ - return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING); - } - } - else + if ( !mydata->OutputStream ) { - /* The destination does not exist. Just move the file. */ - return MoveFile(oldname, newname); + return 0; } -#else - /* On UNIX we have an OS-provided call to do this atomically. */ - return rename(oldname, newname) == 0; -#endif + return data_length; } +//---------------------------------------------------------------------- +int cmCPackTarCompressGenerator::GenerateHeader(std::ostream* os) +{ + (void)os; + return 1; +} diff --git a/Source/CPack/cmCPackTarCompressGenerator.h b/Source/CPack/cmCPackTarCompressGenerator.h index efd5579..75adb22 100644 --- a/Source/CPack/cmCPackTarCompressGenerator.h +++ b/Source/CPack/cmCPackTarCompressGenerator.h @@ -42,6 +42,7 @@ protected: virtual const char* GetOutputExtension() { return "tar.Z"; } int RenameFile(const char* oldname, const char* newname); + int GenerateHeader(std::ostream* os); }; #endif -- cgit v0.12