/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2000-2009 Kitware, Inc., Insight Software Consortium Distributed under the OSI-approved BSD License (the "License"); see accompanying file Copyright.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ #include "cmCPackArchiveGenerator.h" #include "cmCPackLog.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" #include "cmake.h" #include #include #include #include cmCPackArchiveGenerator::cmCPackArchiveGenerator(cmArchiveWrite::Compress t, std::string const& format) { this->Compress = t; this->ArchiveFormat = format; } cmCPackArchiveGenerator::~cmCPackArchiveGenerator() { } int cmCPackArchiveGenerator::InitializeInternal() { this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); return this->Superclass::InitializeInternal(); } int cmCPackArchiveGenerator::addOneComponentToArchive(cmArchiveWrite& archive, cmCPackComponent* component) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, " - 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; std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); // Change to local toplevel cmSystemTools::ChangeDirectory(localToplevel); std::string filePrefix; if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME"); filePrefix += "/"; } const char* installPrefix = this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"); if(installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) { // add to file prefix and remove the leading '/' filePrefix += installPrefix+1; filePrefix += "/"; } std::vector::const_iterator fileIt; for (fileIt = component->Files.begin(); fileIt != component->Files.end(); ++fileIt ) { std::string rp = filePrefix + *fileIt; cmCPackLogger(cmCPackLog::LOG_DEBUG,"Adding file: " << rp << std::endl); archive.Add(rp, 0, 0, false); if (!archive) { cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging files: " << archive.GetError() << std::endl); return 0; } } // Go back to previous dir cmSystemTools::ChangeDirectory(dir); return 1; } /* * The macro will open/create a file 'filename' * an declare and open the associated * cmArchiveWrite 'archive' object. */ #define DECLARE_AND_OPEN_ARCHIVE(filename,archive) \ cmGeneratedFileStream gf; \ gf.Open(filename.c_str(), false, true); \ if (!GenerateHeader(&gf)) \ { \ cmCPackLogger(cmCPackLog::LOG_ERROR, \ "Problem to generate Header for archive < " \ << filename \ << ">." << std::endl); \ return 0; \ } \ cmArchiveWrite archive(gf,this->Compress, this->ArchiveFormat); \ if (!archive) \ { \ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem to create archive < " \ << filename \ << ">. ERROR =" \ << archive.GetError() \ << std::endl); \ return 0; \ } int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { packageFileNames.clear(); // The default behavior is to have one package by component group // unless CPACK_COMPONENTS_IGNORE_GROUP is specified. if (!ignoreGroup) { std::map::iterator compGIt; for (compGIt=this->ComponentGroups.begin(); compGIt!=this->ComponentGroups.end(); ++compGIt) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " << compGIt->first << std::endl); // Begin the archive for this group std::string packageFileName= std::string(toplevel); packageFileName += "/"+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"), compGIt->first, true) + this->GetOutputExtension(); // open a block in order to automatically close archive // at the end of the block { DECLARE_AND_OPEN_ARCHIVE(packageFileName,archive); // now iterate over the component of this group std::vector::iterator compIt; for (compIt=(compGIt->second).Components.begin(); compIt!=(compGIt->second).Components.end(); ++compIt) { // Add the files of this component to the archive addOneComponentToArchive(archive,*compIt); } } // add the generated package to package file names list packageFileNames.push_back(packageFileName); } // Handle Orphan components (components not belonging to any groups) std::map::iterator compIt; for (compIt=this->Components.begin(); compIt!=this->Components.end(); ++compIt ) { // Does the component belong to a group? if (compIt->second.Group==NULL) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Component <" << compIt->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(toplevel); localToplevel += "/"+ compIt->first; packageFileName += "/"+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"), compIt->first, false) + this->GetOutputExtension(); { DECLARE_AND_OPEN_ARCHIVE(packageFileName,archive); // Add the files of this component to the archive addOneComponentToArchive(archive,&(compIt->second)); } // add the generated package to package file names list packageFileNames.push_back(packageFileName); } } } // CPACK_COMPONENTS_IGNORE_GROUPS is set // We build 1 package per component else { std::map::iterator compIt; for (compIt=this->Components.begin(); compIt!=this->Components.end(); ++compIt ) { std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); std::string packageFileName = std::string(toplevel); localToplevel += "/"+ compIt->first; packageFileName += "/"+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"), compIt->first, false) + this->GetOutputExtension(); { DECLARE_AND_OPEN_ARCHIVE(packageFileName,archive); // Add the files of this component to the archive addOneComponentToArchive(archive,&(compIt->second)); } // add the generated package to package file names list packageFileNames.push_back(packageFileName); } } return 1; } int cmCPackArchiveGenerator::PackageComponentsAllInOne() { // reset the package file names packageFileNames.clear(); packageFileNames.push_back(std::string(toplevel)); packageFileNames[0] += "/" +std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + this->GetOutputExtension(); cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging all groups in one package..." "(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE is set)" << std::endl); DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0],archive); // The ALL COMPONENTS in ONE package case std::map::iterator compIt; for (compIt=this->Components.begin();compIt!=this->Components.end(); ++compIt ) { // Add the files of this component to the archive addOneComponentToArchive(archive,&(compIt->second)); } // archive goes out of scope so it will finalized and closed. return 1; } int cmCPackArchiveGenerator::PackageFiles() { cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); if (WantsComponentInstallation()) { // CASE 1 : COMPONENT ALL-IN-ONE package // If ALL COMPONENTS in ONE package has been requested // then the package file is unique and should be open here. if (componentPackageMethod == ONE_PACKAGE) { return PackageComponentsAllInOne(); } // 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. else { return PackageComponents(componentPackageMethod == ONE_PACKAGE_PER_COMPONENT); } } // CASE 3 : NON COMPONENT package. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0],archive); std::vector::const_iterator fileIt; std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); cmSystemTools::ChangeDirectory(toplevel); for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt ) { // Get the relative path to the file std::string rp = cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str()); archive.Add(rp, 0, 0, false); if(!archive) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file< " << *fileIt << "> to archive <" << packageFileNames[0] << "> .ERROR =" << archive.GetError() << std::endl); return 0; } } cmSystemTools::ChangeDirectory(dir); // The destructor of cmArchiveWrite will close and finish the write return 1; } int cmCPackArchiveGenerator::GenerateHeader(std::ostream*) { return 1; } bool cmCPackArchiveGenerator::SupportsComponentInstallation() const { // The Component installation support should only // be activated if explicitly requested by the user // (for backward compatibility reason) if (IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL")) { return true; } else { return false; } }