summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2006-08-21 20:55:03 (GMT)
committerBrad King <brad.king@kitware.com>2006-08-21 20:55:03 (GMT)
commitbed79f6c6b47b2c0661da67799ec37fce8905c54 (patch)
treebdf2a3211652d8587c710d14dbb0f323fb40e617
parentf1ea7e88dc8322d4344e6b7acde6bf7bcffd7806 (diff)
downloadCMake-bed79f6c6b47b2c0661da67799ec37fce8905c54.zip
CMake-bed79f6c6b47b2c0661da67799ec37fce8905c54.tar.gz
CMake-bed79f6c6b47b2c0661da67799ec37fce8905c54.tar.bz2
ENH: Implemented INSTALL(DIRECTORY) command and added a test. Re-organized cmFileCommand's implementation of FILE(INSTALL) a bit to help out. This addresses bug#1694 and partially addresses bug#2691.
-rw-r--r--Source/cmFileCommand.cxx662
-rw-r--r--Source/cmInstallCommand.cxx178
-rw-r--r--Source/cmInstallCommand.h49
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx8
-rw-r--r--Source/cmInstallDirectoryGenerator.h4
-rw-r--r--Source/cmInstallGenerator.cxx10
-rw-r--r--Source/cmInstallGenerator.h3
-rw-r--r--Source/cmInstallTargetGenerator.cxx6
-rw-r--r--Tests/SimpleInstall/CMakeLists.txt23
-rw-r--r--Tests/SimpleInstall/scripts/.gitattributes1
-rwxr-xr-xTests/SimpleInstall/scripts/sample_script2
-rwxr-xr-xTests/SimpleInstall/scripts/sample_script.bat1
-rw-r--r--Tests/SimpleInstallS2/CMakeLists.txt23
-rw-r--r--Tests/SimpleInstallS2/scripts/.gitattributes1
-rwxr-xr-xTests/SimpleInstallS2/scripts/sample_script2
-rwxr-xr-xTests/SimpleInstallS2/scripts/sample_script.bat1
16 files changed, 727 insertions, 247 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index c855418..ee83ea5 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -20,6 +20,34 @@
#include <sys/stat.h>
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+// Table of permissions flags.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+static mode_t mode_owner_read = S_IREAD;
+static mode_t mode_owner_write = S_IWRITE;
+static mode_t mode_owner_execute = S_IEXEC;
+static mode_t mode_group_read = 0;
+static mode_t mode_group_write = 0;
+static mode_t mode_group_execute = 0;
+static mode_t mode_world_read = 0;
+static mode_t mode_world_write = 0;
+static mode_t mode_world_execute = 0;
+static mode_t mode_setuid = 0;
+static mode_t mode_setgid = 0;
+#else
+static mode_t mode_owner_read = S_IRUSR;
+static mode_t mode_owner_write = S_IWUSR;
+static mode_t mode_owner_execute = S_IXUSR;
+static mode_t mode_group_read = S_IRGRP;
+static mode_t mode_group_write = S_IWGRP;
+static mode_t mode_group_execute = S_IXGRP;
+static mode_t mode_world_read = S_IROTH;
+static mode_t mode_world_write = S_IWOTH;
+static mode_t mode_world_execute = S_IXOTH;
+static mode_t mode_setuid = S_ISUID;
+static mode_t mode_setgid = S_ISGID;
+#endif
// cmLibraryCommand
bool cmFileCommand::InitialPass(std::vector<std::string> const& args)
@@ -316,27 +344,120 @@ bool cmFileCommand::HandleMakeDirectoryCommand(
}
//----------------------------------------------------------------------------
+// File installation helper class.
struct cmFileInstaller
{
- bool InstallFile(const char* fromFile, const char* toFile, bool always,
- bool no_permissions);
- bool InstallDirectory(const char* source,
- const char* destination,
- bool always,
- std::string& smanifest_files,
- int destDirLength);
+ // Methods to actually install files.
+ bool InstallFile(const char* fromFile, const char* toFile, bool always);
+ bool InstallDirectory(const char* source, const char* destination,
+ bool always);
+
+ // All instances need the file command and makefile using them.
cmFileInstaller(cmFileCommand* fc, cmMakefile* mf):
- FileCommand(fc), Makefile(mf) {}
+ FileCommand(fc), Makefile(mf), DestDirLength(0)
+ {
+ // Get the current manifest.
+ this->Manifest =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+ }
+ ~cmFileInstaller()
+ {
+ // Save the updated install manifest.
+ this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
+ this->Manifest.c_str());
+ }
+
+private:
cmFileCommand* FileCommand;
cmMakefile* Makefile;
+public:
+
+ // The length of the destdir setting.
+ int DestDirLength;
+
+ // The current file manifest (semicolon separated list).
+ std::string Manifest;
+
+ // Permissions for files and directories installed by this object.
mode_t FilePermissions;
mode_t DirPermissions;
+
+ // Properties set by pattern and regex match rules.
+ struct MatchProperties
+ {
+ bool Exclude;
+ mode_t Permissions;
+ MatchProperties(): Exclude(false), Permissions(0) {}
+ };
+ struct MatchRule
+ {
+ cmsys::RegularExpression Regex;
+ MatchProperties Properties;
+ MatchRule(std::string const& regex): Regex(regex.c_str()) {}
+ };
+ std::vector<MatchRule> MatchRules;
+
+ // Get the properties from rules matching this input file.
+ MatchProperties CollectMatchProperties(const char* file)
+ {
+ MatchProperties result;
+ for(std::vector<MatchRule>::iterator mr = this->MatchRules.begin();
+ mr != this->MatchRules.end(); ++mr)
+ {
+ if(mr->Regex.find(file))
+ {
+ result.Exclude |= mr->Properties.Exclude;
+ result.Permissions |= mr->Properties.Permissions;
+ }
+ }
+ return result;
+ }
+
+ // Append a file to the installation manifest.
+ void ManifestAppend(std::string const& file)
+ {
+ this->Manifest += ";";
+ this->Manifest += file.substr(this->DestDirLength);
+ }
+
+ // Translate an argument to a permissions bit.
+ bool CheckPermissions(std::string const& arg, mode_t& permissions)
+ {
+ if(arg == "OWNER_READ") { permissions |= mode_owner_read; }
+ else if(arg == "OWNER_WRITE") { permissions |= mode_owner_write; }
+ else if(arg == "OWNER_EXECUTE") { permissions |= mode_owner_execute; }
+ else if(arg == "GROUP_READ") { permissions |= mode_group_read; }
+ else if(arg == "GROUP_WRITE") { permissions |= mode_group_write; }
+ else if(arg == "GROUP_EXECUTE") { permissions |= mode_group_execute; }
+ else if(arg == "WORLD_READ") { permissions |= mode_world_read; }
+ else if(arg == "WORLD_WRITE") { permissions |= mode_world_write; }
+ else if(arg == "WORLD_EXECUTE") { permissions |= mode_world_execute; }
+ else if(arg == "SETUID") { permissions |= mode_setuid; }
+ else if(arg == "SETGID") { permissions |= mode_setgid; }
+ else
+ {
+ cmOStringStream e;
+ e << "INSTALL given invalid permission \"" << arg << "\".";
+ this->FileCommand->SetError(e.str().c_str());
+ return false;
+ }
+ return true;
+ }
};
//----------------------------------------------------------------------------
bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
- bool always, bool no_permissions)
+ bool always)
{
+ // Collect any properties matching this file name.
+ MatchProperties match_properties = this->CollectMatchProperties(fromFile);
+
+ // Skip the file if it is excluded.
+ if(match_properties.Exclude)
+ {
+ return true;
+ }
+
// Inform the user about this file installation.
std::string message = "Installing ";
message += toFile;
@@ -352,11 +473,19 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
return false;
}
+ // Add the file to the manifest.
+ this->ManifestAppend(toFile);
+
// Set permissions of the destination file.
- // TODO: Take out no_permissions and replace with a user option to
- // preserve source permissions explicitly.
- if(!no_permissions &&
- !cmSystemTools::SetPermissions(toFile, this->FilePermissions))
+ mode_t permissions = (match_properties.Permissions?
+ match_properties.Permissions : this->FilePermissions);
+ if(!permissions)
+ {
+ // No permissions were explicitly provided but the user requested
+ // that the source file permissions be used.
+ cmSystemTools::GetPermissions(fromFile, permissions);
+ }
+ if(permissions && !cmSystemTools::SetPermissions(toFile, permissions))
{
cmOStringStream e;
e << "Problem setting permissions on file \"" << toFile << "\"";
@@ -370,19 +499,67 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
//----------------------------------------------------------------------------
bool cmFileInstaller::InstallDirectory(const char* source,
const char* destination,
- bool always,
- std::string& smanifest_files,
- int destDirLength)
+ bool always)
{
- cmsys::Directory dir;
- dir.Load(source);
+ // Collect any properties matching this directory name.
+ MatchProperties match_properties = this->CollectMatchProperties(source);
+
+ // Skip the directory if it is excluded.
+ if(match_properties.Exclude)
+ {
+ return true;
+ }
+
+ // Make sure the destination directory exists.
if(!cmSystemTools::MakeDirectory(destination))
{
return false;
}
- // TODO: Make sure destination directory has write permissions
- // before installing files. User requested permissions may be
- // restored later.
+
+ // Compute the requested permissions for the destination directory.
+ mode_t permissions = (match_properties.Permissions?
+ match_properties.Permissions : this->DirPermissions);
+ if(!permissions)
+ {
+ // No permissions were explicitly provided but the user requested
+ // that the source directory permissions be used.
+ cmSystemTools::GetPermissions(source, permissions);
+ }
+
+ // Compute the set of permissions required on this directory to
+ // recursively install files and subdirectories safely.
+ mode_t required_permissions =
+ mode_owner_read | mode_owner_write | mode_owner_execute;
+
+ // If the required permissions are specified it is safe to set the
+ // final permissions now. Otherwise we must add the required
+ // permissions temporarily during file installation.
+ mode_t permissions_before = 0;
+ mode_t permissions_after = 0;
+ if(permissions & required_permissions)
+ {
+ permissions_before = permissions;
+ }
+ else
+ {
+ permissions_before = permissions | required_permissions;
+ permissions_after = permissions;
+ }
+
+ // Set the required permissions of the destination directory.
+ if(permissions_before &&
+ !cmSystemTools::SetPermissions(destination, permissions_before))
+ {
+ cmOStringStream e;
+ e << "Problem setting permissions on directory \""
+ << destination << "\"";
+ this->FileCommand->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Load the directory contents to traverse it recursively.
+ cmsys::Directory dir;
+ dir.Load(source);
unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
for(unsigned long fileNum = 0; fileNum < numFiles; ++fileNum)
{
@@ -397,8 +574,7 @@ bool cmFileInstaller::InstallDirectory(const char* source,
kwsys_stl::string toDir = destination;
toDir += "/";
toDir += dir.GetFile(fileNum);
- if(!this->InstallDirectory(fromPath.c_str(), toDir.c_str(), always,
- smanifest_files, destDirLength))
+ if(!this->InstallDirectory(fromPath.c_str(), toDir.c_str(), always))
{
return false;
}
@@ -409,12 +585,7 @@ bool cmFileInstaller::InstallDirectory(const char* source,
std::string toFile = destination;
toFile += "/";
toFile += dir.GetFile(fileNum);
- if(this->InstallFile(fromPath.c_str(), toFile.c_str(), always, true))
- {
- smanifest_files += ";";
- smanifest_files += toFile.substr(destDirLength);
- }
- else
+ if(!this->InstallFile(fromPath.c_str(), toFile.c_str(), always))
{
return false;
}
@@ -422,8 +593,9 @@ bool cmFileInstaller::InstallDirectory(const char* source,
}
}
- // Set the requested permissions on the destination directory.
- if(!cmSystemTools::SetPermissions(destination, this->DirPermissions))
+ // Set the requested permissions of the destination directory.
+ if(permissions_after &&
+ !cmSystemTools::SetPermissions(destination, permissions_after))
{
cmOStringStream e;
e << "Problem setting permissions on directory \"" << destination << "\"";
@@ -444,6 +616,9 @@ bool cmFileCommand::HandleInstallCommand(
return false;
}
+ // Construct a file installer object.
+ cmFileInstaller installer(this, this->Makefile);
+
std::string rename = "";
std::string destination = "";
std::string stype = "FILES";
@@ -459,60 +634,52 @@ bool cmFileCommand::HandleInstallCommand(
std::map<cmStdString, const char*> properties;
- // Build a table of permissions flags.
-#if defined(_WIN32) && !defined(__CYGWIN__)
- mode_t mode_owner_read = S_IREAD;
- mode_t mode_owner_write = S_IWRITE;
- mode_t mode_owner_execute = S_IEXEC;
- mode_t mode_group_read = 0;
- mode_t mode_group_write = 0;
- mode_t mode_group_execute = 0;
- mode_t mode_world_read = 0;
- mode_t mode_world_write = 0;
- mode_t mode_world_execute = 0;
- mode_t mode_setuid = 0;
- mode_t mode_setgid = 0;
-#else
- mode_t mode_owner_read = S_IRUSR;
- mode_t mode_owner_write = S_IWUSR;
- mode_t mode_owner_execute = S_IXUSR;
- mode_t mode_group_read = S_IRGRP;
- mode_t mode_group_write = S_IWGRP;
- mode_t mode_group_execute = S_IXGRP;
- mode_t mode_world_read = S_IROTH;
- mode_t mode_world_write = S_IWOTH;
- mode_t mode_world_execute = S_IXOTH;
- mode_t mode_setuid = S_ISUID;
- mode_t mode_setgid = S_ISGID;
-#endif
-
- bool in_files = false;
- bool in_properties = false;
- bool in_permissions_file = false;
- bool in_permissions_dir = false;
- bool in_components = false;
- bool in_configurations = false;
+ bool doing_files = false;
+ bool doing_properties = false;
+ bool doing_permissions_file = false;
+ bool doing_permissions_dir = false;
+ bool doing_permissions_match = false;
+ bool doing_components = false;
+ bool doing_configurations = false;
bool use_given_permissions_file = false;
bool use_given_permissions_dir = false;
+ bool use_source_permissions = false;
mode_t permissions_file = 0;
mode_t permissions_dir = 0;
bool optional = false;
+ cmFileInstaller::MatchRule* current_match_rule = 0;
for ( ; i != args.size(); ++i )
{
const std::string* cstr = &args[i];
if ( *cstr == "DESTINATION" && i < args.size()-1 )
{
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
i++;
destination = args[i];
- in_files = false;
- in_properties = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ doing_files = false;
+ doing_properties = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
}
else if ( *cstr == "TYPE" && i < args.size()-1 )
{
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
i++;
stype = args[i];
if ( args[i+1] == "OPTIONAL" )
@@ -520,184 +687,226 @@ bool cmFileCommand::HandleInstallCommand(
i++;
optional = true;
}
- in_properties = false;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
}
else if ( *cstr == "RENAME" && i < args.size()-1 )
{
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
i++;
rename = args[i];
- in_properties = false;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
+ }
+ else if ( *cstr == "REGEX" && i < args.size()-1 )
+ {
+ i++;
+ installer.MatchRules.push_back(cmFileInstaller::MatchRule(args[i]));
+ current_match_rule = &*(installer.MatchRules.end()-1);
+ if(!current_match_rule->Regex.is_valid())
+ {
+ cmOStringStream e;
+ e << "INSTALL could not compile REGEX \"" << args[i] << "\".";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
+ }
+ else if ( *cstr == "EXCLUDE" )
+ {
+ // Add this property to the current match rule.
+ if(!current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \""
+ << *cstr << "\" before a REGEX is given.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ current_match_rule->Properties.Exclude = true;
+ doing_permissions_match = true;
}
else if ( *cstr == "PROPERTIES" )
{
- in_properties = true;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ doing_properties = true;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
}
else if ( *cstr == "PERMISSIONS" )
{
- use_given_permissions_file = true;
- in_properties = false;
- in_files = false;
- in_permissions_file = true;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ if(current_match_rule)
+ {
+ doing_permissions_match = true;
+ doing_permissions_file = false;
+ }
+ else
+ {
+ doing_permissions_match = false;
+ doing_permissions_file = true;
+ use_given_permissions_file = true;
+ }
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
}
else if ( *cstr == "DIR_PERMISSIONS" )
{
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
use_given_permissions_dir = true;
- in_properties = false;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = true;
- in_components = false;
- in_configurations = false;
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = true;
+ doing_components = false;
+ doing_configurations = false;
+ }
+ else if ( *cstr == "USE_SOURCE_PERMISSIONS" )
+ {
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
+ use_source_permissions = true;
}
else if ( *cstr == "COMPONENTS" )
{
- in_properties = false;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = true;
- in_configurations = false;
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = true;
+ doing_configurations = false;
}
else if ( *cstr == "CONFIGURATIONS" )
{
- in_properties = false;
- in_files = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = true;
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ doing_properties = false;
+ doing_files = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = true;
}
- else if ( *cstr == "FILES" && !in_files)
+ else if ( *cstr == "FILES" && !doing_files)
{
- in_files = true;
- in_properties = false;
- in_permissions_file = false;
- in_permissions_dir = false;
- in_components = false;
- in_configurations = false;
+ if(current_match_rule)
+ {
+ cmOStringStream e;
+ e << "INSTALL does not allow \"" << *cstr << "\" after REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ doing_files = true;
+ doing_properties = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_components = false;
+ doing_configurations = false;
}
- else if ( in_properties && i < args.size()-1 )
+ else if ( doing_properties && i < args.size()-1 )
{
properties[args[i]] = args[i+1].c_str();
i++;
}
- else if ( in_files )
+ else if ( doing_files )
{
files.push_back(*cstr);
}
- else if ( in_components )
+ else if ( doing_components )
{
components.insert(*cstr);
}
- else if ( in_configurations )
+ else if ( doing_configurations )
{
configurations.insert(cmSystemTools::UpperCase(*cstr));
}
- else if(in_permissions_file && args[i] == "OWNER_READ")
- {
- permissions_file |= mode_owner_read;
- }
- else if(in_permissions_file && args[i] == "OWNER_WRITE")
+ else if(doing_permissions_file)
{
- permissions_file |= mode_owner_write;
- }
- else if(in_permissions_file && args[i] == "OWNER_EXECUTE")
- {
- permissions_file |= mode_owner_execute;
- }
- else if(in_permissions_file && args[i] == "GROUP_READ")
- {
- permissions_file |= mode_group_read;
- }
- else if(in_permissions_file && args[i] == "GROUP_WRITE")
- {
- permissions_file |= mode_group_write;
- }
- else if(in_permissions_file && args[i] == "GROUP_EXECUTE")
- {
- permissions_file |= mode_group_execute;
- }
- else if(in_permissions_file && args[i] == "WORLD_READ")
- {
- permissions_file |= mode_world_read;
- }
- else if(in_permissions_file && args[i] == "WORLD_WRITE")
- {
- permissions_file |= mode_world_write;
- }
- else if(in_permissions_file && args[i] == "WORLD_EXECUTE")
- {
- permissions_file |= mode_world_execute;
- }
- else if(in_permissions_file && args[i] == "SETUID")
- {
- permissions_file |= mode_setuid;
- }
- else if(in_permissions_file && args[i] == "SETGID")
- {
- permissions_file |= mode_setgid;
- }
- else if(in_permissions_dir && args[i] == "OWNER_READ")
- {
- permissions_dir |= mode_owner_read;
- }
- else if(in_permissions_dir && args[i] == "OWNER_WRITE")
- {
- permissions_dir |= mode_owner_write;
- }
- else if(in_permissions_dir && args[i] == "OWNER_EXECUTE")
- {
- permissions_dir |= mode_owner_execute;
- }
- else if(in_permissions_dir && args[i] == "GROUP_READ")
- {
- permissions_dir |= mode_group_read;
- }
- else if(in_permissions_dir && args[i] == "GROUP_WRITE")
- {
- permissions_dir |= mode_group_write;
- }
- else if(in_permissions_dir && args[i] == "GROUP_EXECUTE")
- {
- permissions_dir |= mode_group_execute;
- }
- else if(in_permissions_dir && args[i] == "WORLD_READ")
- {
- permissions_dir |= mode_world_read;
- }
- else if(in_permissions_dir && args[i] == "WORLD_WRITE")
- {
- permissions_dir |= mode_world_write;
- }
- else if(in_permissions_dir && args[i] == "WORLD_EXECUTE")
- {
- permissions_dir |= mode_world_execute;
+ if(!installer.CheckPermissions(args[i], permissions_file))
+ {
+ return false;
+ }
}
- else if(in_permissions_dir && args[i] == "SETUID")
+ else if(doing_permissions_dir)
{
- permissions_dir |= mode_setuid;
+ if(!installer.CheckPermissions(args[i], permissions_dir))
+ {
+ return false;
+ }
}
- else if(in_permissions_dir && args[i] == "SETGID")
+ else if(doing_permissions_match)
{
- permissions_dir |= mode_setgid;
+ if(!installer.CheckPermissions(
+ args[i], current_match_rule->Properties.Permissions))
+ {
+ return false;
+ }
}
else
{
@@ -746,7 +955,6 @@ bool cmFileCommand::HandleInstallCommand(
}
}
- int destDirLength = 0;
if ( destdir && *destdir )
{
std::string sdestdir = destdir;
@@ -800,7 +1008,7 @@ bool cmFileCommand::HandleInstallCommand(
}
}
destination = sdestdir + (destination.c_str() + skip);
- destDirLength = int(sdestdir.size());
+ installer.DestDirLength = int(sdestdir.size());
}
if ( files.size() == 0 )
@@ -871,7 +1079,7 @@ bool cmFileCommand::HandleInstallCommand(
// If file permissions were not specified set default permissions
// for this target type.
- if(!use_given_permissions_file)
+ if(!use_given_permissions_file && !use_source_permissions)
{
switch(itype)
{
@@ -910,7 +1118,7 @@ bool cmFileCommand::HandleInstallCommand(
}
// If directory permissions were not specified set default permissions.
- if(!use_given_permissions_dir)
+ if(!use_given_permissions_dir && !use_source_permissions)
{
// Use read/write/executable permissions.
permissions_dir = 0;
@@ -923,20 +1131,10 @@ bool cmFileCommand::HandleInstallCommand(
permissions_dir |= mode_world_execute;
}
- // Construct a file installer object.
- cmFileInstaller installer(this, this->Makefile);
+ // Set the installer permissions.
installer.FilePermissions = permissions_file;
installer.DirPermissions = permissions_dir;
- // Get the current manifest.
- const char* manifest_files =
- this->Makefile->GetDefinition("CMAKE_INSTALL_MANIFEST_FILES");
- std::string smanifest_files;
- if ( manifest_files )
- {
- smanifest_files = manifest_files;
- }
-
// Check whether files should be copied always or only if they have
// changed.
bool copy_always =
@@ -1008,8 +1206,7 @@ bool cmFileCommand::HandleInstallCommand(
this->SetError(errstring.c_str());
return false;
}
- smanifest_files += ";";
- smanifest_files += libname.substr(destDirLength);;
+ installer.ManifestAppend(libname);
if ( toFile != soname )
{
if ( !cmSystemTools::CreateSymlink(fromName.c_str(),
@@ -1020,8 +1217,7 @@ bool cmFileCommand::HandleInstallCommand(
this->SetError(errstring.c_str());
return false;
}
- smanifest_files += ";";
- smanifest_files += soname.substr(destDirLength);
+ installer.ManifestAppend(soname);
}
}
}
@@ -1056,8 +1252,7 @@ bool cmFileCommand::HandleInstallCommand(
this->SetError(errstring.c_str());
return false;
}
- smanifest_files += ";";
- smanifest_files += exename.substr(destDirLength);
+ installer.ManifestAppend(exename);
}
}
break;
@@ -1077,8 +1272,7 @@ bool cmFileCommand::HandleInstallCommand(
{
// Try installing this directory.
if(!installer.InstallDirectory(fromFile.c_str(), toFile.c_str(),
- copy_always, smanifest_files,
- destDirLength))
+ copy_always))
{
return false;
}
@@ -1087,7 +1281,7 @@ bool cmFileCommand::HandleInstallCommand(
{
// Install this file.
if(!installer.InstallFile(fromFile.c_str(), toFile.c_str(),
- copy_always, false))
+ copy_always))
{
return false;
}
@@ -1109,10 +1303,6 @@ bool cmFileCommand::HandleInstallCommand(
}
}
#endif
-
- // Add the file to the manifest.
- smanifest_files += ";";
- smanifest_files += toFile.substr(destDirLength);
}
else if(!optional)
{
@@ -1125,10 +1315,6 @@ bool cmFileCommand::HandleInstallCommand(
}
}
- // Save the updated install manifest.
- this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
- smanifest_files.c_str());
-
return true;
}
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 833beae..0e05ab7 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -21,6 +21,8 @@
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
+#include <cmsys/Glob.hxx>
+
// cmInstallCommand
bool cmInstallCommand::InitialPass(std::vector<std::string> const& args)
{
@@ -686,33 +688,117 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
{
bool doing_dirs = true;
bool doing_destination = false;
+ bool doing_pattern = false;
+ bool doing_regex = false;
bool doing_permissions_file = false;
bool doing_permissions_dir = false;
+ bool doing_permissions_match = false;
bool doing_configurations = false;
bool doing_component = false;
+ bool in_match_mode = false;
std::vector<std::string> dirs;
const char* destination = 0;
std::string permissions_file;
std::string permissions_dir;
std::vector<std::string> configurations;
std::string component;
+ std::string literal_args;
for(unsigned int i=1; i < args.size(); ++i)
{
if(args[i] == "DESTINATION")
{
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
// Switch to setting the destination property.
doing_dirs = false;
doing_destination = true;
+ doing_pattern = false;
+ doing_regex = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_configurations = false;
+ doing_component = false;
+ }
+ else if(args[i] == "PATTERN")
+ {
+ // Switch to a new pattern match rule.
+ doing_dirs = false;
+ doing_destination = false;
+ doing_pattern = true;
+ doing_regex = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_permissions_match = false;
+ doing_configurations = false;
+ doing_component = false;
+ in_match_mode = true;
+ }
+ else if(args[i] == "REGEX")
+ {
+ // Switch to a new regex match rule.
+ doing_dirs = false;
+ doing_destination = false;
+ doing_pattern = false;
+ doing_regex = true;
doing_permissions_file = false;
doing_permissions_dir = false;
+ doing_permissions_match = false;
doing_configurations = false;
doing_component = false;
+ in_match_mode = true;
+ }
+ else if(args[i] == "EXCLUDE")
+ {
+ // Add this property to the current match rule.
+ if(!in_match_mode || doing_pattern || doing_regex)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" before a PATTERN or REGEX is given.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ literal_args += " EXCLUDE";
+ doing_permissions_match = false;
+ }
+ else if(args[i] == "PERMISSIONS")
+ {
+ if(!in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" before a PATTERN or REGEX is given.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Switch to setting the current match permissions property.
+ literal_args += " PERMISSIONS";
+ doing_permissions_match = true;
}
else if(args[i] == "FILE_PERMISSIONS")
{
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
// Switch to setting the file permissions property.
doing_dirs = false;
doing_destination = false;
+ doing_pattern = false;
+ doing_regex = false;
doing_permissions_file = true;
doing_permissions_dir = false;
doing_configurations = false;
@@ -720,19 +806,63 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
}
else if(args[i] == "DIRECTORY_PERMISSIONS")
{
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
// Switch to setting the directory permissions property.
doing_dirs = false;
doing_destination = false;
+ doing_pattern = false;
+ doing_regex = false;
doing_permissions_file = false;
doing_permissions_dir = true;
doing_configurations = false;
doing_component = false;
}
+ else if(args[i] == "USE_SOURCE_PERMISSIONS")
+ {
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Add this option literally.
+ doing_dirs = false;
+ doing_destination = false;
+ doing_pattern = false;
+ doing_regex = false;
+ doing_permissions_file = false;
+ doing_permissions_dir = false;
+ doing_configurations = false;
+ doing_component = false;
+ literal_args += " USE_SOURCE_PERMISSIONS";
+ }
else if(args[i] == "CONFIGURATIONS")
{
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
// Switch to setting the configurations property.
doing_dirs = false;
doing_destination = false;
+ doing_pattern = false;
+ doing_regex = false;
doing_permissions_file = false;
doing_permissions_dir = false;
doing_configurations = true;
@@ -740,9 +870,20 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
}
else if(args[i] == "COMPONENT")
{
+ if(in_match_mode)
+ {
+ cmOStringStream e;
+ e << args[0] << " does not allow \""
+ << args[i] << "\" after PATTERN or REGEX.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
// Switch to setting the component property.
doing_dirs = false;
doing_destination = false;
+ doing_pattern = false;
+ doing_regex = false;
doing_permissions_file = false;
doing_permissions_dir = false;
doing_configurations = false;
@@ -781,6 +922,28 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
destination = args[i].c_str();
doing_destination = false;
}
+ else if(doing_pattern)
+ {
+ // 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.
+ literal_args += " REGEX \"/";
+ std::string regex = cmsys::Glob::PatternToRegex(args[i], false);
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "$\"";
+ doing_pattern = false;
+ }
+ else if(doing_regex)
+ {
+ literal_args += " REGEX \"";
+ std::string regex = args[i];
+ cmSystemTools::ReplaceString(regex, "\\", "\\\\");
+ literal_args += regex;
+ literal_args += "\"";
+ doing_regex = false;
+ }
else if(doing_component)
{
component = args[i];
@@ -810,6 +973,18 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
return false;
}
}
+ else if(doing_permissions_match)
+ {
+ // Check the requested permission.
+ if(!this->CheckPermissions(args[i], literal_args))
+ {
+ cmOStringStream e;
+ e << args[0] << " given invalid permission \""
+ << args[i] << "\".";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
else
{
// Unknown argument.
@@ -844,7 +1019,8 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
permissions_file.c_str(),
permissions_dir.c_str(),
configurations,
- component.c_str()));
+ component.c_str(),
+ literal_args.c_str()));
// Tell the global generator about any installation component names
// specified.
diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h
index 7bf77df..0607d16 100644
--- a/Source/cmInstallCommand.h
+++ b/Source/cmInstallCommand.h
@@ -165,6 +165,55 @@ public:
"such as shell scripts. Use the TARGETS form to install targets "
"built within the project."
"\n"
+ "The DIRECTORY signature:\n"
+ " INSTALL(DIRECTORY dirs... DESTINATION <dir>\n"
+ " [FILE_PERMISSIONS permissions...]\n"
+ " [DIRECTORY_PERMISSIONS permissions...]\n"
+ " [USE_SOURCE_PERMISSIONS]\n"
+ " [CONFIGURATIONS [Debug|Release|...]]\n"
+ " [COMPONENT <component>]\n"
+ " [[PATTERN <pattern> | REGEX <regex>]\n"
+ " [EXCLUDE] [PERMISSIONS permissions...]] [...])\n"
+ "The DIRECTORY form installs contents of one or more directories "
+ "to a given destination. "
+ "The directory structure is copied verbatim to the destination. "
+ "The last component of each directory name is appended to the "
+ "destination directory but a trailing slash may be used to "
+ "avoid this because it leaves the last component empty. "
+ "Directory names given as relative paths are interpreted with "
+ "respect to the current source directory. "
+ "The FILE_PERMISSIONS and DIRECTORY_PERMISSIONS options specify "
+ "permissions given to files and directories in the destination. "
+ "If USE_SOURCE_PERMISSIONS is specified and FILE_PERMISSIONS is not, "
+ "file permissions will be copied from the source directory structure. "
+ "If no permissions are specified files will be given the default "
+ "permissions specified in the FILES form of the command, and the "
+ "directories will be given the default permissions specified in the "
+ "PROGRAMS form of the command. "
+ "The PATTERN and REGEX options specify a globbing pattern or regular "
+ "expression to match directories or files encountered during traversal "
+ "of an input directory. The full path to an input file or directory "
+ "(with forward slashes) is matched against the expression. "
+ "A PATTERN will match only complete file names: the portion of the full "
+ "path matching the pattern must occur at the end of the file name and "
+ "be preceded by a slash. "
+ "A REGEX will match any portion of the full path but it may use "
+ "'/' and '$' to simulate the PATTERN behavior. "
+ "Options following one of these matching expressions "
+ "are applied only to files or directories matching them. The EXCLUDE "
+ "option will skip the matched file or directory. The PERMISSIONS "
+ "option overrides the permissions setting for the matched file. "
+ "For example the code\n"
+ " INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj\n"
+ " PATTERN \"CVS\" EXCLUDE\n"
+ " PATTERN \"scripts/*\"\n"
+ " PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ\n"
+ " GROUP_EXECUTE GROUP_READ)\n"
+ "will install the icons directory to share/myproj/icons and the "
+ "scripts directory to share/myproj. The icons will get default file "
+ "permissions, the scripts will be given specific permissions, and "
+ "any CVS directories will be excluded."
+ "\n"
"The SCRIPT and CODE signature:\n"
" INSTALL([[SCRIPT <file>] [CODE <code>]] [...])\n"
"The SCRIPT form will invoke the given CMake script files during "
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index 9ff09a6..aaf8235 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -25,10 +25,12 @@ cmInstallDirectoryGenerator
const char* file_permissions,
const char* dir_permissions,
std::vector<std::string> const& configurations,
- const char* component):
+ const char* component,
+ const char* literal_args):
Directories(dirs), Destination(dest),
FilePermissions(file_permissions), DirPermissions(dir_permissions),
- Configurations(configurations), Component(component)
+ Configurations(configurations), Component(component),
+ LiteralArguments(literal_args)
{
}
@@ -54,6 +56,6 @@ void cmInstallDirectoryGenerator::GenerateScript(std::ostream& os)
this->FilePermissions.c_str(),
this->DirPermissions.c_str(),
this->Configurations, this->Component.c_str(),
- no_rename);
+ no_rename, this->LiteralArguments.c_str());
}
}
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index 6b36434..296130e 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -30,7 +30,8 @@ public:
const char* file_permissions,
const char* dir_permissions,
std::vector<std::string> const& configurations,
- const char* component);
+ const char* component,
+ const char* literal_args);
virtual ~cmInstallDirectoryGenerator();
protected:
@@ -41,6 +42,7 @@ protected:
std::string DirPermissions;
std::vector<std::string> Configurations;
std::string Component;
+ std::string LiteralArguments;
};
#endif
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 034410b..275eb11 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -59,7 +59,8 @@ void cmInstallGenerator
const char* permissions_dir /* = 0 */,
std::vector<std::string> const& configurations,
const char* component /* = 0 */,
- const char* rename /* = 0 */
+ const char* rename /* = 0 */,
+ const char* literal_args /* = 0 */
)
{
// Use the FILE command to install the file.
@@ -109,5 +110,10 @@ void cmInstallGenerator
{
os << " COMPONENTS \"" << component << "\"";
}
- os << " FILES \"" << file << "\")\n";
+ os << " FILES \"" << file << "\"";
+ if(literal_args && *literal_args)
+ {
+ os << literal_args;
+ }
+ os << ")\n";
}
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index df165c0..94c0fbd 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -43,7 +43,8 @@ public:
std::vector<std::string> const& configurations
= std::vector<std::string>(),
const char* component = 0,
- const char* rename = 0
+ const char* rename = 0,
+ const char* literal_args = 0
);
protected:
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index a15ce3c..1e99cd9 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -72,6 +72,7 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
std::string destination = this->Destination;
// Setup special properties for some target types.
+ std::string literal_args;
std::string props;
const char* properties = 0;
cmTarget::TargetType type = this->Target->GetType();
@@ -140,6 +141,7 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
false, false);
fromFile += ".app";
type = cmTarget::INSTALL_DIRECTORY;
+ literal_args += " USE_SOURCE_PERMISSIONS";
}
}
break;
@@ -159,11 +161,13 @@ void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
// Write code to install the target file.
const char* no_dir_permissions = 0;
+ const char* no_rename = 0;
this->AddInstallRule(os, destination.c_str(), type, fromFile.c_str(),
this->ImportLibrary, properties,
this->FilePermissions.c_str(), no_dir_permissions,
this->Configurations,
- this->Component.c_str());
+ this->Component.c_str(),
+ no_rename, literal_args.c_str());
// Fix the install_name settings in installed binaries.
if(type == cmTarget::SHARED_LIBRARY ||
diff --git a/Tests/SimpleInstall/CMakeLists.txt b/Tests/SimpleInstall/CMakeLists.txt
index 4df7f77..f543d43 100644
--- a/Tests/SimpleInstall/CMakeLists.txt
+++ b/Tests/SimpleInstall/CMakeLists.txt
@@ -80,6 +80,22 @@ IF(STAGE2)
MESSAGE(FATAL_ERROR "Release-configuration file installed for Debug!")
ENDIF(EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/include/Debug/lib1release.h")
+ # Check for failure of directory installation.
+ IF(NOT EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/share/TestSubDir/TSD.h")
+ MESSAGE(FATAL_ERROR "Directory installation did not install TSD.h")
+ ENDIF(NOT EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/share/TestSubDir/TSD.h")
+ EXECUTE_PROCESS(
+ COMMAND "${CMAKE_INSTALL_PREFIX}/MyTest/share/sample_script"
+ RESULT_VARIABLE SAMPLE_SCRIPT_RESULT
+ OUTPUT_VARIABLE SAMPLE_SCRIPT_OUTPUT
+ )
+ IF(NOT "${SAMPLE_SCRIPT_RESULT}" MATCHES "^0$")
+ MESSAGE(FATAL_ERROR "Sample script failed: [${SAMPLE_SCRIPT_RESULT}]")
+ ENDIF(NOT "${SAMPLE_SCRIPT_RESULT}" MATCHES "^0$")
+ IF(NOT "${SAMPLE_SCRIPT_OUTPUT}" MATCHES "Sample Script Output")
+ MESSAGE(FATAL_ERROR "Bad sample script output: [${SAMPLE_SCRIPT_OUTPUT}]")
+ ENDIF(NOT "${SAMPLE_SCRIPT_OUTPUT}" MATCHES "Sample Script Output")
+
# Make sure the test executable can run from the install tree.
SET_TARGET_PROPERTIES(SimpleInstallS2 PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/MyTest/lib)
@@ -138,6 +154,13 @@ ELSE(STAGE2)
DESTINATION MyTest/include/Debug
)
+ # Test directory installation.
+ INSTALL(
+ DIRECTORY TestSubDir scripts/ DESTINATION MyTest/share
+ PATTERN "CVS" EXCLUDE
+ PATTERN "scripts/*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ )
+
# Test user-specified install scripts.
INSTALL(
SCRIPT InstallScript1.cmake
diff --git a/Tests/SimpleInstall/scripts/.gitattributes b/Tests/SimpleInstall/scripts/.gitattributes
new file mode 100644
index 0000000..5e3db2f
--- /dev/null
+++ b/Tests/SimpleInstall/scripts/.gitattributes
@@ -0,0 +1 @@
+sample_script crlf=input
diff --git a/Tests/SimpleInstall/scripts/sample_script b/Tests/SimpleInstall/scripts/sample_script
new file mode 100755
index 0000000..81f9f53
--- /dev/null
+++ b/Tests/SimpleInstall/scripts/sample_script
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "Sample Script Output"
diff --git a/Tests/SimpleInstall/scripts/sample_script.bat b/Tests/SimpleInstall/scripts/sample_script.bat
new file mode 100755
index 0000000..64a77b5
--- /dev/null
+++ b/Tests/SimpleInstall/scripts/sample_script.bat
@@ -0,0 +1 @@
+@echo Sample Script Output
diff --git a/Tests/SimpleInstallS2/CMakeLists.txt b/Tests/SimpleInstallS2/CMakeLists.txt
index 4df7f77..f543d43 100644
--- a/Tests/SimpleInstallS2/CMakeLists.txt
+++ b/Tests/SimpleInstallS2/CMakeLists.txt
@@ -80,6 +80,22 @@ IF(STAGE2)
MESSAGE(FATAL_ERROR "Release-configuration file installed for Debug!")
ENDIF(EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/include/Debug/lib1release.h")
+ # Check for failure of directory installation.
+ IF(NOT EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/share/TestSubDir/TSD.h")
+ MESSAGE(FATAL_ERROR "Directory installation did not install TSD.h")
+ ENDIF(NOT EXISTS "${CMAKE_INSTALL_PREFIX}/MyTest/share/TestSubDir/TSD.h")
+ EXECUTE_PROCESS(
+ COMMAND "${CMAKE_INSTALL_PREFIX}/MyTest/share/sample_script"
+ RESULT_VARIABLE SAMPLE_SCRIPT_RESULT
+ OUTPUT_VARIABLE SAMPLE_SCRIPT_OUTPUT
+ )
+ IF(NOT "${SAMPLE_SCRIPT_RESULT}" MATCHES "^0$")
+ MESSAGE(FATAL_ERROR "Sample script failed: [${SAMPLE_SCRIPT_RESULT}]")
+ ENDIF(NOT "${SAMPLE_SCRIPT_RESULT}" MATCHES "^0$")
+ IF(NOT "${SAMPLE_SCRIPT_OUTPUT}" MATCHES "Sample Script Output")
+ MESSAGE(FATAL_ERROR "Bad sample script output: [${SAMPLE_SCRIPT_OUTPUT}]")
+ ENDIF(NOT "${SAMPLE_SCRIPT_OUTPUT}" MATCHES "Sample Script Output")
+
# Make sure the test executable can run from the install tree.
SET_TARGET_PROPERTIES(SimpleInstallS2 PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/MyTest/lib)
@@ -138,6 +154,13 @@ ELSE(STAGE2)
DESTINATION MyTest/include/Debug
)
+ # Test directory installation.
+ INSTALL(
+ DIRECTORY TestSubDir scripts/ DESTINATION MyTest/share
+ PATTERN "CVS" EXCLUDE
+ PATTERN "scripts/*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ )
+
# Test user-specified install scripts.
INSTALL(
SCRIPT InstallScript1.cmake
diff --git a/Tests/SimpleInstallS2/scripts/.gitattributes b/Tests/SimpleInstallS2/scripts/.gitattributes
new file mode 100644
index 0000000..5e3db2f
--- /dev/null
+++ b/Tests/SimpleInstallS2/scripts/.gitattributes
@@ -0,0 +1 @@
+sample_script crlf=input
diff --git a/Tests/SimpleInstallS2/scripts/sample_script b/Tests/SimpleInstallS2/scripts/sample_script
new file mode 100755
index 0000000..81f9f53
--- /dev/null
+++ b/Tests/SimpleInstallS2/scripts/sample_script
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "Sample Script Output"
diff --git a/Tests/SimpleInstallS2/scripts/sample_script.bat b/Tests/SimpleInstallS2/scripts/sample_script.bat
new file mode 100755
index 0000000..64a77b5
--- /dev/null
+++ b/Tests/SimpleInstallS2/scripts/sample_script.bat
@@ -0,0 +1 @@
+@echo Sample Script Output