ENH: Improve FILE GLOB_RECURSE handling of symlinks with a new CMake policy. CMP0009 establishes NEW default behavior of not recursing through symlinks. OLD default behavior or explicit FOLLOW_SYMLINKS argument to FILE GLOB_RECURSE will still recurse through symlinks.
This commit is contained in:
parent
0e5319f21d
commit
bd1935dcd1
@ -668,18 +668,39 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
|
|||||||
i++;
|
i++;
|
||||||
cmsys::Glob g;
|
cmsys::Glob g;
|
||||||
g.SetRecurse(recurse);
|
g.SetRecurse(recurse);
|
||||||
|
|
||||||
|
bool explicitFollowSymlinks = false;
|
||||||
|
cmPolicies::PolicyStatus status =
|
||||||
|
this->Makefile->GetPolicyStatus(cmPolicies::CMP0009);
|
||||||
|
if(recurse)
|
||||||
|
{
|
||||||
|
switch(status)
|
||||||
|
{
|
||||||
|
case cmPolicies::NEW:
|
||||||
|
g.RecurseThroughSymlinksOff();
|
||||||
|
break;
|
||||||
|
case cmPolicies::OLD:
|
||||||
|
case cmPolicies::WARN:
|
||||||
|
case cmPolicies::REQUIRED_IF_USED:
|
||||||
|
case cmPolicies::REQUIRED_ALWAYS:
|
||||||
|
g.RecurseThroughSymlinksOn();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string output = "";
|
std::string output = "";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for ( ; i != args.end(); ++i )
|
for ( ; i != args.end(); ++i )
|
||||||
{
|
{
|
||||||
if ( *i == "RECURSE_SYMLINKS_OFF" )
|
if ( recurse && (*i == "FOLLOW_SYMLINKS") )
|
||||||
{
|
{
|
||||||
g.RecurseThroughSymlinksOff();
|
explicitFollowSymlinks = true;
|
||||||
|
g.RecurseThroughSymlinksOn();
|
||||||
++i;
|
++i;
|
||||||
if ( i == args.end() )
|
if ( i == args.end() )
|
||||||
{
|
{
|
||||||
this->SetError(
|
this->SetError(
|
||||||
"GLOB requires a glob expression after RECURSE_SYMLINKS_OFF");
|
"GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -732,6 +753,37 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(recurse && !explicitFollowSymlinks)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case cmPolicies::NEW:
|
||||||
|
// Correct behavior, yay!
|
||||||
|
break;
|
||||||
|
case cmPolicies::OLD:
|
||||||
|
// Probably not really the expected behavior, but the author explicitly
|
||||||
|
// asked for the old behavior... no warning.
|
||||||
|
case cmPolicies::WARN:
|
||||||
|
// Possibly unexpected old behavior *and* we actually traversed
|
||||||
|
// symlinks without being explicitly asked to: warn the author.
|
||||||
|
if(g.GetFollowedSymlinkCount() != 0)
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
|
||||||
|
this->Makefile->GetPolicies()->
|
||||||
|
GetPolicyWarning(cmPolicies::CMP0009));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case cmPolicies::REQUIRED_IF_USED:
|
||||||
|
case cmPolicies::REQUIRED_ALWAYS:
|
||||||
|
this->SetError("policy CMP0009 error");
|
||||||
|
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
|
||||||
|
this->Makefile->GetPolicies()->
|
||||||
|
GetRequiredPolicyError(cmPolicies::CMP0009));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->Makefile->AddDefinition(variable.c_str(), output.c_str());
|
this->Makefile->AddDefinition(variable.c_str(), output.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public:
|
|||||||
" [NO_HEX_CONVERSION])\n"
|
" [NO_HEX_CONVERSION])\n"
|
||||||
" file(GLOB variable [RELATIVE path] [globbing expressions]...)\n"
|
" file(GLOB variable [RELATIVE path] [globbing expressions]...)\n"
|
||||||
" file(GLOB_RECURSE variable [RELATIVE path] \n"
|
" file(GLOB_RECURSE variable [RELATIVE path] \n"
|
||||||
" [RECURSE_SYMLINKS_OFF] [globbing expressions]...)\n"
|
" [FOLLOW_SYMLINKS] [globbing expressions]...)\n"
|
||||||
" file(REMOVE [file1 ...])\n"
|
" file(REMOVE [file1 ...])\n"
|
||||||
" file(REMOVE_RECURSE [file1 ...])\n"
|
" file(REMOVE_RECURSE [file1 ...])\n"
|
||||||
" file(MAKE_DIRECTORY [directory1 directory2 ...])\n"
|
" file(MAKE_DIRECTORY [directory1 directory2 ...])\n"
|
||||||
@ -124,11 +124,11 @@ public:
|
|||||||
" *.cxx - match all files with extension cxx\n"
|
" *.cxx - match all files with extension cxx\n"
|
||||||
" *.vt? - match all files with extension vta,...,vtz\n"
|
" *.vt? - match all files with extension vta,...,vtz\n"
|
||||||
" f[3-5].txt - match files f3.txt, f4.txt, f5.txt\n"
|
" f[3-5].txt - match files f3.txt, f4.txt, f5.txt\n"
|
||||||
"GLOB_RECURSE will generate similar list as the regular GLOB, except "
|
"GLOB_RECURSE will generate a list similar to the regular GLOB, except "
|
||||||
"it will traverse all the subdirectories of the matched directory and "
|
"it will traverse all the subdirectories of the matched directory and "
|
||||||
"match the files. Subdirectories that are symlinks are traversed by "
|
"match the files. Subdirectories that are symlinks are only traversed "
|
||||||
"default to match the behavior of older CMake releases. Use "
|
"if FOLLOW_SYMLINKS is given or cmake policy CMP0009 is not set to NEW. "
|
||||||
"RECURSE_SYMLINKS_OFF to prevent recursion through symlinks.\n"
|
"See cmake --help-policy CMP0009 for more information.\n"
|
||||||
"Examples of recursive globbing include:\n"
|
"Examples of recursive globbing include:\n"
|
||||||
" /dir/*.py - match all python files in /dir and subdirectories\n"
|
" /dir/*.py - match all python files in /dir and subdirectories\n"
|
||||||
"MAKE_DIRECTORY will create the given directories, also if their parent "
|
"MAKE_DIRECTORY will create the given directories, also if their parent "
|
||||||
|
@ -307,6 +307,22 @@ cmPolicies::cmPolicies()
|
|||||||
"The NEW behavior for this policy is to trust the given path and "
|
"The NEW behavior for this policy is to trust the given path and "
|
||||||
"pass it directly to the native build tool unchanged.",
|
"pass it directly to the native build tool unchanged.",
|
||||||
2,6,1, cmPolicies::WARN);
|
2,6,1, cmPolicies::WARN);
|
||||||
|
|
||||||
|
this->DefinePolicy(
|
||||||
|
CMP0009, "CMP0009",
|
||||||
|
"FILE GLOB_RECURSE calls should not follow symlinks by default.",
|
||||||
|
"In CMake 2.6.1 and below, FILE GLOB_RECURSE calls would follow "
|
||||||
|
"through symlinks, sometimes coming up with unexpectedly large "
|
||||||
|
"result sets because of symlinks to top level directories that "
|
||||||
|
"contain hundreds of thousands of files."
|
||||||
|
"\n"
|
||||||
|
"This policy determines whether or not to follow symlinks "
|
||||||
|
"encountered during a FILE GLOB_RECURSE call. "
|
||||||
|
"The OLD behavior for this policy is to follow the symlinks. "
|
||||||
|
"The NEW behavior for this policy is not to follow the symlinks "
|
||||||
|
"by default, but only if FOLLOW_SYMLINKS is given as an additional "
|
||||||
|
"argument to the FILE command.",
|
||||||
|
2,6,2, cmPolicies::WARN);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPolicies::~cmPolicies()
|
cmPolicies::~cmPolicies()
|
||||||
@ -384,7 +400,7 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile *mf,
|
|||||||
"In order to get compatibility features supporting versions earlier "
|
"In order to get compatibility features supporting versions earlier "
|
||||||
"than 2.4 set policy CMP0001 to OLD to tell CMake to check the "
|
"than 2.4 set policy CMP0001 to OLD to tell CMake to check the "
|
||||||
"CMAKE_BACKWARDS_COMPATIBILITY variable. "
|
"CMAKE_BACKWARDS_COMPATIBILITY variable. "
|
||||||
"One way to so this is to set the policy version to 2.4 exactly."
|
"One way to do this is to set the policy version to 2.4 exactly."
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ public:
|
|||||||
CMP0006, // BUNDLE install rules needed for MACOSX_BUNDLE targets
|
CMP0006, // BUNDLE install rules needed for MACOSX_BUNDLE targets
|
||||||
CMP0007, // list command handling of empty elements
|
CMP0007, // list command handling of empty elements
|
||||||
CMP0008, // Full-path libraries must be a valid library file name
|
CMP0008, // Full-path libraries must be a valid library file name
|
||||||
|
CMP0009, // GLOB_RECURSE should not follow symlinks by default
|
||||||
|
|
||||||
// Always the last entry. Useful mostly to avoid adding a comma
|
// Always the last entry. Useful mostly to avoid adding a comma
|
||||||
// the last policy when adding a new one.
|
// the last policy when adding a new one.
|
||||||
|
@ -67,6 +67,7 @@ Glob::Glob()
|
|||||||
this->RecurseThroughSymlinks = true;
|
this->RecurseThroughSymlinks = true;
|
||||||
// RecurseThroughSymlinks is true by default for backwards compatibility,
|
// RecurseThroughSymlinks is true by default for backwards compatibility,
|
||||||
// not because it's a good idea...
|
// not because it's a good idea...
|
||||||
|
this->FollowedSymlinkCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -266,9 +267,13 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
|
|||||||
}
|
}
|
||||||
if ( kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
|
if ( kwsys::SystemTools::FileIsDirectory(realname.c_str()) )
|
||||||
{
|
{
|
||||||
if (!kwsys::SystemTools::FileIsSymlink(realname.c_str()) ||
|
bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname.c_str());
|
||||||
this->RecurseThroughSymlinks)
|
if (!isSymLink || this->RecurseThroughSymlinks)
|
||||||
{
|
{
|
||||||
|
if (isSymLink)
|
||||||
|
{
|
||||||
|
++this->FollowedSymlinkCount;
|
||||||
|
}
|
||||||
this->RecurseDirectory(start+1, realname, dir_only);
|
this->RecurseDirectory(start+1, realname, dir_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,9 @@ public:
|
|||||||
void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; }
|
void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; }
|
||||||
bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; }
|
bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; }
|
||||||
|
|
||||||
|
//! Get the number of symlinks followed through recursion
|
||||||
|
unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; }
|
||||||
|
|
||||||
//! Set relative to true to only show relative path to files.
|
//! Set relative to true to only show relative path to files.
|
||||||
void SetRelative(const char* dir);
|
void SetRelative(const char* dir);
|
||||||
const char* GetRelative();
|
const char* GetRelative();
|
||||||
@ -98,6 +101,7 @@ protected:
|
|||||||
bool Recurse;
|
bool Recurse;
|
||||||
kwsys_stl::string Relative;
|
kwsys_stl::string Relative;
|
||||||
bool RecurseThroughSymlinks;
|
bool RecurseThroughSymlinks;
|
||||||
|
unsigned int FollowedSymlinkCount;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Glob(const Glob&); // Not implemented.
|
Glob(const Glob&); // Not implemented.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user