ENH: Create file(COPY) command signature
The file(INSTALL) command has long been undocumented and used only to implement install() scripts. We now document it and provide a similar file(COPY) signature which is useful in general-purpose scripts. It provides the capabilities of install(DIRECTORY) and install(FILES) but operates immediately instead of contributing to install scripts.
This commit is contained in:
parent
b6cb117346
commit
c58ca24286
|
@ -112,6 +112,10 @@ bool cmFileCommand
|
|||
{
|
||||
return this->HandleRemove(args, true);
|
||||
}
|
||||
else if ( subCommand == "COPY" )
|
||||
{
|
||||
return this->HandleCopyCommand(args);
|
||||
}
|
||||
else if ( subCommand == "INSTALL" )
|
||||
{
|
||||
return this->HandleInstallCommand(args);
|
||||
|
@ -903,9 +907,10 @@ cmFileCommand::HandleDifferentCommand(std::vector<std::string> const& args)
|
|||
// File installation helper class.
|
||||
struct cmFileCopier
|
||||
{
|
||||
cmFileCopier(cmFileCommand* command):
|
||||
cmFileCopier(cmFileCommand* command, const char* name = "COPY"):
|
||||
FileCommand(command),
|
||||
Makefile(command->GetMakefile()),
|
||||
Name(name),
|
||||
Always(false),
|
||||
MatchlessFiles(true),
|
||||
FilePermissions(0),
|
||||
|
@ -913,7 +918,7 @@ struct cmFileCopier
|
|||
CurrentMatchRule(0),
|
||||
UseGivenPermissionsFile(false),
|
||||
UseGivenPermissionsDir(false),
|
||||
UseSourcePermissions(false),
|
||||
UseSourcePermissions(true),
|
||||
Doing(DoingNone)
|
||||
{
|
||||
}
|
||||
|
@ -923,6 +928,7 @@ protected:
|
|||
|
||||
cmFileCommand* FileCommand;
|
||||
cmMakefile* Makefile;
|
||||
const char* Name;
|
||||
bool Always;
|
||||
cmFileTimeComparison FileTimes;
|
||||
|
||||
|
@ -984,7 +990,7 @@ protected:
|
|||
if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot set permissions on \"" << toFile << "\"";
|
||||
e << this->Name << " cannot set permissions on \"" << toFile << "\"";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -1008,7 +1014,7 @@ protected:
|
|||
else
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL given invalid permission \"" << arg << "\".";
|
||||
e << this->Name << " given invalid permission \"" << arg << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -1035,7 +1041,7 @@ protected:
|
|||
{
|
||||
// The input file does not exist and installation is not optional.
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot find \"" << fromFile << "\".";
|
||||
e << this->Name << " cannot find \"" << fromFile << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -1055,6 +1061,7 @@ protected:
|
|||
DoingError,
|
||||
DoingDestination,
|
||||
DoingFiles,
|
||||
DoingPattern,
|
||||
DoingRegex,
|
||||
DoingPermissionsFile,
|
||||
DoingPermissionsDir,
|
||||
|
@ -1067,14 +1074,14 @@ protected:
|
|||
void NotBeforeMatch(std::string const& arg)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "option " << arg << " may not appear before REGEX.";
|
||||
e << "option " << arg << " may not appear before PATTERN or REGEX.";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
void NotAfterMatch(std::string const& arg)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "option " << arg << " may not appear after REGEX.";
|
||||
e << "option " << arg << " may not appear after PATTERN or REGEX.";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
|
@ -1128,7 +1135,7 @@ bool cmFileCopier::Parse(std::vector<std::string> const& args)
|
|||
if(this->Destination.empty())
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL given no DESTINATION";
|
||||
e << this->Name << " given no DESTINATION";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -1162,6 +1169,10 @@ bool cmFileCopier::CheckKeyword(std::string const& arg)
|
|||
this->Doing = DoingDestination;
|
||||
}
|
||||
}
|
||||
else if(arg == "PATTERN")
|
||||
{
|
||||
this->Doing = DoingPattern;
|
||||
}
|
||||
else if(arg == "REGEX")
|
||||
{
|
||||
this->Doing = DoingRegex;
|
||||
|
@ -1179,6 +1190,41 @@ bool cmFileCopier::CheckKeyword(std::string const& arg)
|
|||
this->NotBeforeMatch(arg);
|
||||
}
|
||||
}
|
||||
else if(arg == "PERMISSIONS")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
{
|
||||
this->Doing = DoingPermissionsMatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->NotBeforeMatch(arg);
|
||||
}
|
||||
}
|
||||
else if(arg == "FILE_PERMISSIONS")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
{
|
||||
this->NotAfterMatch(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Doing = DoingPermissionsFile;
|
||||
this->UseGivenPermissionsFile = true;
|
||||
}
|
||||
}
|
||||
else if(arg == "DIRECTORY_PERMISSIONS")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
{
|
||||
this->NotAfterMatch(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Doing = DoingPermissionsDir;
|
||||
this->UseGivenPermissionsDir = true;
|
||||
}
|
||||
}
|
||||
else if(arg == "USE_SOURCE_PERMISSIONS")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
|
@ -1191,6 +1237,18 @@ bool cmFileCopier::CheckKeyword(std::string const& arg)
|
|||
this->UseSourcePermissions = true;
|
||||
}
|
||||
}
|
||||
else if(arg == "NO_SOURCE_PERMISSIONS")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
{
|
||||
this->NotAfterMatch(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Doing = DoingNone;
|
||||
this->UseSourcePermissions = false;
|
||||
}
|
||||
}
|
||||
else if(arg == "FILES_MATCHING")
|
||||
{
|
||||
if(this->CurrentMatchRule)
|
||||
|
@ -1239,6 +1297,30 @@ bool cmFileCopier::CheckValue(std::string const& arg)
|
|||
}
|
||||
this->Doing = DoingNone;
|
||||
break;
|
||||
case DoingPattern:
|
||||
{
|
||||
// Convert the pattern to a regular expression. Require a
|
||||
// leading slash and trailing end-of-string in the matched
|
||||
// string to make sure the pattern matches only whole file
|
||||
// names.
|
||||
std::string regex = "/";
|
||||
regex += cmsys::Glob::PatternToRegex(arg, false);
|
||||
regex += "$";
|
||||
this->MatchRules.push_back(MatchRule(regex));
|
||||
this->CurrentMatchRule = &*(this->MatchRules.end()-1);
|
||||
if(this->CurrentMatchRule->Regex.is_valid())
|
||||
{
|
||||
this->Doing = DoingNone;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "could not compile PATTERN \"" << arg << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DoingRegex:
|
||||
this->MatchRules.push_back(MatchRule(arg));
|
||||
this->CurrentMatchRule = &*(this->MatchRules.end()-1);
|
||||
|
@ -1370,7 +1452,7 @@ bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
|
|||
if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot read symlink \"" << fromFile
|
||||
e << this->Name << " cannot read symlink \"" << fromFile
|
||||
<< "\" to duplicate at \"" << toFile << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
|
@ -1403,7 +1485,7 @@ bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
|
|||
if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot duplicate symlink \"" << fromFile
|
||||
e << this->Name << " cannot duplicate symlink \"" << fromFile
|
||||
<< "\" at \"" << toFile << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
|
@ -1435,7 +1517,7 @@ bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
|
|||
if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true, false))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot copy file \"" << fromFile
|
||||
e << this->Name << " cannot copy file \"" << fromFile
|
||||
<< "\" to \"" << toFile << "\".";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
|
@ -1447,7 +1529,8 @@ bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
|
|||
if (!cmSystemTools::CopyFileTime(fromFile, toFile))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot set modification time on \"" << toFile << "\"";
|
||||
e << this->Name << " cannot set modification time on \""
|
||||
<< toFile << "\"";
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -1477,7 +1560,7 @@ bool cmFileCopier::InstallDirectory(const char* source,
|
|||
if(!cmSystemTools::MakeDirectory(destination))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "INSTALL cannot make directory \"" << destination << "\": "
|
||||
e << this->Name << " cannot make directory \"" << destination << "\": "
|
||||
<< cmSystemTools::GetLastSystemError();
|
||||
this->FileCommand->SetError(e.str().c_str());
|
||||
return false;
|
||||
|
@ -1548,15 +1631,24 @@ bool cmFileCopier::InstallDirectory(const char* source,
|
|||
return this->SetPermissions(destination, permissions_after);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
|
||||
{
|
||||
cmFileCopier copier(this);
|
||||
return copier.Run(args);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct cmFileInstaller: public cmFileCopier
|
||||
{
|
||||
cmFileInstaller(cmFileCommand* command):
|
||||
cmFileCopier(command),
|
||||
cmFileCopier(command, "INSTALL"),
|
||||
InstallType(cmTarget::INSTALL_FILES),
|
||||
Optional(false),
|
||||
DestDirLength(0)
|
||||
{
|
||||
// Installation does not use source permissions by default.
|
||||
this->UseSourcePermissions = false;
|
||||
// Check whether to copy files always or only if they have changed.
|
||||
this->Always =
|
||||
cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS"));
|
||||
|
@ -1736,6 +1828,7 @@ bool cmFileInstaller::CheckKeyword(std::string const& arg)
|
|||
}
|
||||
else
|
||||
{
|
||||
// file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
|
||||
this->Doing = DoingPermissionsFile;
|
||||
this->UseGivenPermissionsFile = true;
|
||||
}
|
||||
|
@ -1748,6 +1841,7 @@ bool cmFileInstaller::CheckKeyword(std::string const& arg)
|
|||
}
|
||||
else
|
||||
{
|
||||
// file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
|
||||
this->Doing = DoingPermissionsDir;
|
||||
this->UseGivenPermissionsDir = true;
|
||||
}
|
||||
|
|
|
@ -157,7 +157,42 @@ public:
|
|||
"and the second element is a string value for the error. A 0 "
|
||||
"numeric error means no error in the operation. "
|
||||
"If TIMEOUT time is specified, the operation will "
|
||||
"timeout after time seconds, time can be specified as a float.\n";
|
||||
"timeout after time seconds, time can be specified as a float."
|
||||
"\n"
|
||||
"The file() command also provides COPY and INSTALL signatures:\n"
|
||||
" file(<COPY|INSTALL> files... DESTINATION <dir>\n"
|
||||
" [FILE_PERMISSIONS permissions...]\n"
|
||||
" [DIRECTORY_PERMISSIONS permissions...]\n"
|
||||
" [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]\n"
|
||||
" [FILES_MATCHING]\n"
|
||||
" [[PATTERN <pattern> | REGEX <regex>]\n"
|
||||
" [EXCLUDE] [PERMISSIONS permissions...]] [...])\n"
|
||||
"The COPY signature copies files, directories, and symlinks to a "
|
||||
"destination folder. "
|
||||
"Relative input paths are evaluated with respect to the current "
|
||||
"source directory, and a relative destination is evaluated with "
|
||||
"respect to the current build directory. "
|
||||
"Copying preserves input file timestamps, and optimizes out a file "
|
||||
"if it exists at the destination with the same timestamp. "
|
||||
"Copying preserves input permissions unless explicit permissions or "
|
||||
"NO_SOURCE_PERMISSIONS are given (default is USE_SOURCE_PERMISSIONS). "
|
||||
"See the install(DIRECTORY) command for documentation of permissions, "
|
||||
"PATTERN, REGEX, and EXCLUDE options. "
|
||||
"\n"
|
||||
"The INSTALL signature differs slightly from COPY: "
|
||||
"it prints status messages, and NO_SOURCE_PERMISSIONS is default. "
|
||||
"Installation scripts generated by the install() command use this "
|
||||
"signature (with some undocumented options for internal use)."
|
||||
// Undocumented INSTALL options:
|
||||
// - RENAME <name>
|
||||
// - OPTIONAL
|
||||
// - FILES keyword to re-enter files... list
|
||||
// - PERMISSIONS before REGEX is alias for FILE_PERMISSIONS
|
||||
// - DIR_PERMISSIONS is alias for DIRECTORY_PERMISSIONS
|
||||
// - TYPE <FILE|DIRECTORY|EXECUTABLE|PROGRAM|
|
||||
// STATIC_LIBRARY|SHARED_LIBRARY|MODULE>
|
||||
// - COMPONENTS, CONFIGURATIONS, PROPERTIES (ignored for compat)
|
||||
;
|
||||
}
|
||||
|
||||
cmTypeMacro(cmFileCommand, cmCommand);
|
||||
|
@ -179,6 +214,7 @@ protected:
|
|||
bool HandleRPathRemoveCommand(std::vector<std::string> const& args);
|
||||
bool HandleDifferentCommand(std::vector<std::string> const& args);
|
||||
|
||||
bool HandleCopyCommand(std::vector<std::string> const& args);
|
||||
bool HandleInstallCommand(std::vector<std::string> const& args);
|
||||
bool HandleDownloadCommand(std::vector<std::string> const& args);
|
||||
};
|
||||
|
|
|
@ -188,10 +188,19 @@ FILE(WRITE "${CMAKE_CURRENT_BINARY_DIR}/OutputFile.h-tmp" "${outfile}")
|
|||
FILE(RENAME "${CMAKE_CURRENT_BINARY_DIR}/OutputFile.h-tmp"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/OutputFile.h")
|
||||
|
||||
# Test file copy with relative paths
|
||||
FILE(COPY .
|
||||
DESTINATION src
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE
|
||||
DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE # test no OWNER_WRITE
|
||||
FILES_MATCHING PATTERN *.cxx # Only copy the main source file
|
||||
REGEX /src$ EXCLUDE # Block recursion for in-source build
|
||||
)
|
||||
|
||||
# Test file glob
|
||||
FILE(GLOB_RECURSE src_files "${CMAKE_CURRENT_SOURCE_DIR}/*")
|
||||
MESSAGE("Files in ${CMAKE_CURRENT_SOURCE_DIR} are ${src_files}")
|
||||
SET(expr "${CMAKE_CURRENT_SOURCE_DIR}/[sS][!a-su-zA-Z0-9][^a-qs-zA-Z0-9]ing?ile*.cxx")
|
||||
SET(expr "${CMAKE_CURRENT_BINARY_DIR}/src/[sS][!a-su-zA-Z0-9][^a-qs-zA-Z0-9]ing?ile*.cxx")
|
||||
MESSAGE("Glob expression is [${expr}].")
|
||||
FILE(GLOB src_files "${expr}")
|
||||
MESSAGE("Globbed files [${src_files}].")
|
||||
|
|
Loading…
Reference in New Issue