summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmFileCommand.cxx122
-rw-r--r--Source/cmFileCommand.h38
-rw-r--r--Tests/StringFileTest/CMakeLists.txt11
3 files changed, 155 insertions, 16 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index c7348b7..cceea97 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -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;
@@ -1549,14 +1632,23 @@ bool cmFileCopier::InstallDirectory(const char* source,
}
//----------------------------------------------------------------------------
+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;
}
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
index 04bb661..cadb1a9 100644
--- a/Source/cmFileCommand.h
+++ b/Source/cmFileCommand.h
@@ -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);
};
diff --git a/Tests/StringFileTest/CMakeLists.txt b/Tests/StringFileTest/CMakeLists.txt
index b50d203..398243c 100644
--- a/Tests/StringFileTest/CMakeLists.txt
+++ b/Tests/StringFileTest/CMakeLists.txt
@@ -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}].")