mirror of
https://github.com/reactos/CMake.git
synced 2025-02-26 06:55:34 +00:00
cmFileCommand: Factor out cmFileCopier and cmFileInstaller
Split these classes out into their own sources.
This commit is contained in:
parent
80b761b924
commit
e2e8f6b132
@ -224,6 +224,10 @@ set(SRCS
|
||||
cmFileAPICodemodel.h
|
||||
cmFileAPICMakeFiles.cxx
|
||||
cmFileAPICMakeFiles.h
|
||||
cmFileCopier.cxx
|
||||
cmFileCopier.h
|
||||
cmFileInstaller.cxx
|
||||
cmFileInstaller.h
|
||||
cmFileLock.cxx
|
||||
cmFileLock.h
|
||||
cmFileLockPool.cxx
|
||||
|
File diff suppressed because it is too large
Load Diff
660
Source/cmFileCopier.cxx
Normal file
660
Source/cmFileCopier.cxx
Normal file
@ -0,0 +1,660 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmFileCopier.h"
|
||||
|
||||
#include "cmFSPermissions.h"
|
||||
#include "cmFileCommand.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmsys/Directory.hxx"
|
||||
#include "cmsys/Glob.hxx"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "cmsys/FStream.hxx"
|
||||
#endif
|
||||
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
using namespace cmFSPermissions;
|
||||
|
||||
cmFileCopier::cmFileCopier(cmFileCommand* command, const char* name)
|
||||
: FileCommand(command)
|
||||
, Makefile(command->GetMakefile())
|
||||
, Name(name)
|
||||
, Always(false)
|
||||
, MatchlessFiles(true)
|
||||
, FilePermissions(0)
|
||||
, DirPermissions(0)
|
||||
, CurrentMatchRule(nullptr)
|
||||
, UseGivenPermissionsFile(false)
|
||||
, UseGivenPermissionsDir(false)
|
||||
, UseSourcePermissions(true)
|
||||
, Doing(DoingNone)
|
||||
{
|
||||
}
|
||||
|
||||
cmFileCopier::~cmFileCopier() = default;
|
||||
|
||||
cmFileCopier::MatchProperties cmFileCopier::CollectMatchProperties(
|
||||
const std::string& file)
|
||||
{
|
||||
// Match rules are case-insensitive on some platforms.
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
|
||||
const std::string file_to_match = cmSystemTools::LowerCase(file);
|
||||
#else
|
||||
const std::string& file_to_match = file;
|
||||
#endif
|
||||
|
||||
// Collect properties from all matching rules.
|
||||
bool matched = false;
|
||||
MatchProperties result;
|
||||
for (MatchRule& mr : this->MatchRules) {
|
||||
if (mr.Regex.find(file_to_match)) {
|
||||
matched = true;
|
||||
result.Exclude |= mr.Properties.Exclude;
|
||||
result.Permissions |= mr.Properties.Permissions;
|
||||
}
|
||||
}
|
||||
if (!matched && !this->MatchlessFiles) {
|
||||
result.Exclude = !cmSystemTools::FileIsDirectory(file);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cmFileCopier::SetPermissions(const std::string& toFile,
|
||||
mode_t permissions)
|
||||
{
|
||||
if (permissions) {
|
||||
#ifdef WIN32
|
||||
if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
|
||||
// Store the mode in an NTFS alternate stream.
|
||||
std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
|
||||
|
||||
// Writing to an NTFS alternate stream changes the modification
|
||||
// time, so we need to save and restore its original value.
|
||||
cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
|
||||
cmSystemTools::FileTimeGet(toFile, file_time_orig);
|
||||
|
||||
cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
|
||||
|
||||
if (permissionStream) {
|
||||
permissionStream << std::oct << permissions << std::endl;
|
||||
}
|
||||
|
||||
permissionStream.close();
|
||||
|
||||
cmSystemTools::FileTimeSet(toFile, file_time_orig);
|
||||
|
||||
cmSystemTools::FileTimeDelete(file_time_orig);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!cmSystemTools::SetPermissions(toFile, permissions)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot set permissions on \"" << toFile << "\"";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Translate an argument to a permissions bit.
|
||||
bool cmFileCopier::CheckPermissions(std::string const& arg,
|
||||
mode_t& permissions)
|
||||
{
|
||||
if (!cmFSPermissions::stringToModeT(arg, permissions)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " given invalid permission \"" << arg << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string const& cmFileCopier::ToName(std::string const& fromName)
|
||||
{
|
||||
return fromName;
|
||||
}
|
||||
|
||||
bool cmFileCopier::ReportMissing(const std::string& fromFile)
|
||||
{
|
||||
// The input file does not exist and installation is not optional.
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot find \"" << fromFile << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void cmFileCopier::NotBeforeMatch(std::string const& arg)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "option " << arg << " may not appear before PATTERN or REGEX.";
|
||||
this->FileCommand->SetError(e.str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
|
||||
void cmFileCopier::NotAfterMatch(std::string const& arg)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "option " << arg << " may not appear after PATTERN or REGEX.";
|
||||
this->FileCommand->SetError(e.str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
|
||||
void cmFileCopier::DefaultFilePermissions()
|
||||
{
|
||||
// Use read/write permissions.
|
||||
this->FilePermissions = 0;
|
||||
this->FilePermissions |= mode_owner_read;
|
||||
this->FilePermissions |= mode_owner_write;
|
||||
this->FilePermissions |= mode_group_read;
|
||||
this->FilePermissions |= mode_world_read;
|
||||
}
|
||||
|
||||
void cmFileCopier::DefaultDirectoryPermissions()
|
||||
{
|
||||
// Use read/write/executable permissions.
|
||||
this->DirPermissions = 0;
|
||||
this->DirPermissions |= mode_owner_read;
|
||||
this->DirPermissions |= mode_owner_write;
|
||||
this->DirPermissions |= mode_owner_execute;
|
||||
this->DirPermissions |= mode_group_read;
|
||||
this->DirPermissions |= mode_group_execute;
|
||||
this->DirPermissions |= mode_world_read;
|
||||
this->DirPermissions |= mode_world_execute;
|
||||
}
|
||||
|
||||
bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
|
||||
{
|
||||
// check if default dir creation permissions were set
|
||||
const char* default_dir_install_permissions = this->Makefile->GetDefinition(
|
||||
"CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
|
||||
if (default_dir_install_permissions && *default_dir_install_permissions) {
|
||||
std::vector<std::string> items;
|
||||
cmSystemTools::ExpandListArgument(default_dir_install_permissions, items);
|
||||
for (const auto& arg : items) {
|
||||
if (!this->CheckPermissions(arg, **mode)) {
|
||||
std::ostringstream e;
|
||||
e << this->FileCommand->GetError()
|
||||
<< " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
|
||||
"variable.";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*mode = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::Parse(std::vector<std::string> const& args)
|
||||
{
|
||||
this->Doing = DoingFiles;
|
||||
for (unsigned int i = 1; i < args.size(); ++i) {
|
||||
// Check this argument.
|
||||
if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
|
||||
std::ostringstream e;
|
||||
e << "called with unknown argument \"" << args[i] << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Quit if an argument is invalid.
|
||||
if (this->Doing == DoingError) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Require a destination.
|
||||
if (this->Destination.empty()) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " given no DESTINATION";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// If file permissions were not specified set default permissions.
|
||||
if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
|
||||
this->DefaultFilePermissions();
|
||||
}
|
||||
|
||||
// If directory permissions were not specified set default permissions.
|
||||
if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
|
||||
this->DefaultDirectoryPermissions();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::CheckKeyword(std::string const& arg)
|
||||
{
|
||||
if (arg == "DESTINATION") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingDestination;
|
||||
}
|
||||
} else if (arg == "FILES_FROM_DIR") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingFilesFromDir;
|
||||
}
|
||||
} else if (arg == "PATTERN") {
|
||||
this->Doing = DoingPattern;
|
||||
} else if (arg == "REGEX") {
|
||||
this->Doing = DoingRegex;
|
||||
} else if (arg == "EXCLUDE") {
|
||||
// Add this property to the current match rule.
|
||||
if (this->CurrentMatchRule) {
|
||||
this->CurrentMatchRule->Properties.Exclude = true;
|
||||
this->Doing = DoingNone;
|
||||
} else {
|
||||
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) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
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) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
this->MatchlessFiles = false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::CheckValue(std::string const& arg)
|
||||
{
|
||||
switch (this->Doing) {
|
||||
case DoingFiles:
|
||||
this->Files.push_back(arg);
|
||||
break;
|
||||
case DoingDestination:
|
||||
if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
|
||||
this->Destination = arg;
|
||||
} else {
|
||||
this->Destination = this->Makefile->GetCurrentBinaryDirectory();
|
||||
this->Destination += "/" + arg;
|
||||
}
|
||||
this->Doing = DoingNone;
|
||||
break;
|
||||
case DoingFilesFromDir:
|
||||
if (cmSystemTools::FileIsFullPath(arg)) {
|
||||
this->FilesFromDir = arg;
|
||||
} else {
|
||||
this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
|
||||
this->FilesFromDir += "/" + arg;
|
||||
}
|
||||
cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
|
||||
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.emplace_back(regex);
|
||||
this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
|
||||
if (this->CurrentMatchRule->Regex.is_valid()) {
|
||||
this->Doing = DoingNone;
|
||||
} else {
|
||||
std::ostringstream e;
|
||||
e << "could not compile PATTERN \"" << arg << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
} break;
|
||||
case DoingRegex:
|
||||
this->MatchRules.emplace_back(arg);
|
||||
this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
|
||||
if (this->CurrentMatchRule->Regex.is_valid()) {
|
||||
this->Doing = DoingNone;
|
||||
} else {
|
||||
std::ostringstream e;
|
||||
e << "could not compile REGEX \"" << arg << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
break;
|
||||
case DoingPermissionsFile:
|
||||
if (!this->CheckPermissions(arg, this->FilePermissions)) {
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
break;
|
||||
case DoingPermissionsDir:
|
||||
if (!this->CheckPermissions(arg, this->DirPermissions)) {
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
break;
|
||||
case DoingPermissionsMatch:
|
||||
if (!this->CheckPermissions(
|
||||
arg, this->CurrentMatchRule->Properties.Permissions)) {
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::Run(std::vector<std::string> const& args)
|
||||
{
|
||||
if (!this->Parse(args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::string const& f : this->Files) {
|
||||
std::string file;
|
||||
if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
|
||||
if (!this->FilesFromDir.empty()) {
|
||||
file = this->FilesFromDir;
|
||||
} else {
|
||||
file = this->Makefile->GetCurrentSourceDirectory();
|
||||
}
|
||||
file += "/";
|
||||
file += f;
|
||||
} else if (!this->FilesFromDir.empty()) {
|
||||
this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
|
||||
"to be specified as relative paths.");
|
||||
return false;
|
||||
} else {
|
||||
file = f;
|
||||
}
|
||||
|
||||
// Split the input file into its directory and name components.
|
||||
std::vector<std::string> fromPathComponents;
|
||||
cmSystemTools::SplitPath(file, fromPathComponents);
|
||||
std::string fromName = *(fromPathComponents.end() - 1);
|
||||
std::string fromDir = cmSystemTools::JoinPath(
|
||||
fromPathComponents.begin(), fromPathComponents.end() - 1);
|
||||
|
||||
// Compute the full path to the destination file.
|
||||
std::string toFile = this->Destination;
|
||||
if (!this->FilesFromDir.empty()) {
|
||||
std::string dir = cmSystemTools::GetFilenamePath(f);
|
||||
if (!dir.empty()) {
|
||||
toFile += "/";
|
||||
toFile += dir;
|
||||
}
|
||||
}
|
||||
std::string const& toName = this->ToName(fromName);
|
||||
if (!toName.empty()) {
|
||||
toFile += "/";
|
||||
toFile += toName;
|
||||
}
|
||||
|
||||
// Construct the full path to the source file. The file name may
|
||||
// have been changed above.
|
||||
std::string fromFile = fromDir;
|
||||
if (!fromName.empty()) {
|
||||
fromFile += "/";
|
||||
fromFile += fromName;
|
||||
}
|
||||
|
||||
if (!this->Install(fromFile, toFile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::Install(const std::string& fromFile,
|
||||
const std::string& toFile)
|
||||
{
|
||||
if (fromFile.empty()) {
|
||||
std::ostringstream e;
|
||||
e << "INSTALL encountered an empty string input file name.";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (cmSystemTools::SameFile(fromFile, toFile)) {
|
||||
return true;
|
||||
}
|
||||
if (cmSystemTools::FileIsSymlink(fromFile)) {
|
||||
return this->InstallSymlink(fromFile, toFile);
|
||||
}
|
||||
if (cmSystemTools::FileIsDirectory(fromFile)) {
|
||||
return this->InstallDirectory(fromFile, toFile, match_properties);
|
||||
}
|
||||
if (cmSystemTools::FileExists(fromFile)) {
|
||||
return this->InstallFile(fromFile, toFile, match_properties);
|
||||
}
|
||||
return this->ReportMissing(fromFile);
|
||||
}
|
||||
|
||||
bool cmFileCopier::InstallSymlink(const std::string& fromFile,
|
||||
const std::string& toFile)
|
||||
{
|
||||
// Read the original symlink.
|
||||
std::string symlinkTarget;
|
||||
if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot read symlink \"" << fromFile
|
||||
<< "\" to duplicate at \"" << toFile << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare the symlink value to that at the destination if not
|
||||
// always installing.
|
||||
bool copy = true;
|
||||
if (!this->Always) {
|
||||
std::string oldSymlinkTarget;
|
||||
if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
|
||||
if (symlinkTarget == oldSymlinkTarget) {
|
||||
copy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the user about this file installation.
|
||||
this->ReportCopy(toFile, TypeLink, copy);
|
||||
|
||||
if (copy) {
|
||||
// Remove the destination file so we can always create the symlink.
|
||||
cmSystemTools::RemoveFile(toFile);
|
||||
|
||||
// Create destination directory if it doesn't exist
|
||||
cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
|
||||
|
||||
// Create the symlink.
|
||||
if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot duplicate symlink \"" << fromFile
|
||||
<< "\" at \"" << toFile << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileCopier::InstallFile(const std::string& fromFile,
|
||||
const std::string& toFile,
|
||||
MatchProperties match_properties)
|
||||
{
|
||||
// Determine whether we will copy the file.
|
||||
bool copy = true;
|
||||
if (!this->Always) {
|
||||
// If both files exist with the same time do not copy.
|
||||
if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) {
|
||||
copy = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the user about this file installation.
|
||||
this->ReportCopy(toFile, TypeFile, copy);
|
||||
|
||||
// Copy the file.
|
||||
if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
|
||||
<< toFile << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the file modification time of the destination file.
|
||||
if (copy && !this->Always) {
|
||||
// Add write permission so we can set the file time.
|
||||
// Permissions are set unconditionally below anyway.
|
||||
mode_t perm = 0;
|
||||
if (cmSystemTools::GetPermissions(toFile, perm)) {
|
||||
cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
|
||||
}
|
||||
if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot set modification time on \"" << toFile
|
||||
<< "\"";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set permissions of the destination file.
|
||||
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);
|
||||
}
|
||||
return this->SetPermissions(toFile, permissions);
|
||||
}
|
||||
|
||||
bool cmFileCopier::InstallDirectory(const std::string& source,
|
||||
const std::string& destination,
|
||||
MatchProperties match_properties)
|
||||
{
|
||||
// Inform the user about this directory installation.
|
||||
this->ReportCopy(destination, TypeDir,
|
||||
!cmSystemTools::FileIsDirectory(destination));
|
||||
|
||||
// check if default dir creation permissions were set
|
||||
mode_t default_dir_mode_v = 0;
|
||||
mode_t* default_dir_mode = &default_dir_mode_v;
|
||||
if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the destination directory exists.
|
||||
if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
|
||||
std::ostringstream e;
|
||||
e << this->Name << " cannot make directory \"" << destination
|
||||
<< "\": " << cmSystemTools::GetLastSystemError();
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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) == required_permissions) {
|
||||
permissions_before = permissions;
|
||||
} else {
|
||||
permissions_before = permissions | required_permissions;
|
||||
permissions_after = permissions;
|
||||
}
|
||||
|
||||
// Set the required permissions of the destination directory.
|
||||
if (!this->SetPermissions(destination, permissions_before)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the directory contents to traverse it recursively.
|
||||
cmsys::Directory dir;
|
||||
if (!source.empty()) {
|
||||
dir.Load(source);
|
||||
}
|
||||
unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
|
||||
for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
|
||||
if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
|
||||
strcmp(dir.GetFile(fileNum), "..") == 0)) {
|
||||
std::string fromPath = source;
|
||||
fromPath += "/";
|
||||
fromPath += dir.GetFile(fileNum);
|
||||
std::string toPath = destination;
|
||||
toPath += "/";
|
||||
toPath += dir.GetFile(fileNum);
|
||||
if (!this->Install(fromPath, toPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the requested permissions of the destination directory.
|
||||
return this->SetPermissions(destination, permissions_after);
|
||||
}
|
120
Source/cmFileCopier.h
Normal file
120
Source/cmFileCopier.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#ifndef cmFileCopier_h
|
||||
#define cmFileCopier_h
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmFileTimeComparison.h"
|
||||
#include "cm_sys_stat.h"
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmFileCommand;
|
||||
class cmMakefile;
|
||||
|
||||
// File installation helper class.
|
||||
struct cmFileCopier
|
||||
{
|
||||
cmFileCopier(cmFileCommand* command, const char* name = "COPY");
|
||||
virtual ~cmFileCopier();
|
||||
|
||||
bool Run(std::vector<std::string> const& args);
|
||||
|
||||
protected:
|
||||
cmFileCommand* FileCommand;
|
||||
cmMakefile* Makefile;
|
||||
const char* Name;
|
||||
bool Always;
|
||||
cmFileTimeComparison FileTimes;
|
||||
|
||||
// Whether to install a file not matching any expression.
|
||||
bool MatchlessFiles;
|
||||
|
||||
// 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 = false;
|
||||
mode_t Permissions = 0;
|
||||
};
|
||||
struct MatchRule
|
||||
{
|
||||
cmsys::RegularExpression Regex;
|
||||
MatchProperties Properties;
|
||||
std::string RegexString;
|
||||
MatchRule(std::string const& regex)
|
||||
: Regex(regex)
|
||||
, RegexString(regex)
|
||||
{
|
||||
}
|
||||
};
|
||||
std::vector<MatchRule> MatchRules;
|
||||
|
||||
// Get the properties from rules matching this input file.
|
||||
MatchProperties CollectMatchProperties(const std::string& file);
|
||||
|
||||
bool SetPermissions(const std::string& toFile, mode_t permissions);
|
||||
|
||||
// Translate an argument to a permissions bit.
|
||||
bool CheckPermissions(std::string const& arg, mode_t& permissions);
|
||||
|
||||
bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
|
||||
bool InstallFile(const std::string& fromFile, const std::string& toFile,
|
||||
MatchProperties match_properties);
|
||||
bool InstallDirectory(const std::string& source,
|
||||
const std::string& destination,
|
||||
MatchProperties match_properties);
|
||||
virtual bool Install(const std::string& fromFile, const std::string& toFile);
|
||||
virtual std::string const& ToName(std::string const& fromName);
|
||||
|
||||
enum Type
|
||||
{
|
||||
TypeFile,
|
||||
TypeDir,
|
||||
TypeLink
|
||||
};
|
||||
virtual void ReportCopy(const std::string&, Type, bool) {}
|
||||
virtual bool ReportMissing(const std::string& fromFile);
|
||||
|
||||
MatchRule* CurrentMatchRule;
|
||||
bool UseGivenPermissionsFile;
|
||||
bool UseGivenPermissionsDir;
|
||||
bool UseSourcePermissions;
|
||||
std::string Destination;
|
||||
std::string FilesFromDir;
|
||||
std::vector<std::string> Files;
|
||||
int Doing;
|
||||
|
||||
virtual bool Parse(std::vector<std::string> const& args);
|
||||
enum
|
||||
{
|
||||
DoingNone,
|
||||
DoingError,
|
||||
DoingDestination,
|
||||
DoingFilesFromDir,
|
||||
DoingFiles,
|
||||
DoingPattern,
|
||||
DoingRegex,
|
||||
DoingPermissionsFile,
|
||||
DoingPermissionsDir,
|
||||
DoingPermissionsMatch,
|
||||
DoingLast1
|
||||
};
|
||||
virtual bool CheckKeyword(std::string const& arg);
|
||||
virtual bool CheckValue(std::string const& arg);
|
||||
|
||||
void NotBeforeMatch(std::string const& arg);
|
||||
void NotAfterMatch(std::string const& arg);
|
||||
virtual void DefaultFilePermissions();
|
||||
virtual void DefaultDirectoryPermissions();
|
||||
|
||||
bool GetDefaultDirectoryPermissions(mode_t** mode);
|
||||
};
|
||||
|
||||
#endif
|
350
Source/cmFileInstaller.cxx
Normal file
350
Source/cmFileInstaller.cxx
Normal file
@ -0,0 +1,350 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmFileInstaller.h"
|
||||
|
||||
#include "cmFSPermissions.h"
|
||||
#include "cmFileCommand.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
#include "cm_sys_stat.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace cmFSPermissions;
|
||||
|
||||
cmFileInstaller::cmFileInstaller(cmFileCommand* command)
|
||||
: cmFileCopier(command, "INSTALL")
|
||||
, InstallType(cmInstallType_FILES)
|
||||
, Optional(false)
|
||||
, MessageAlways(false)
|
||||
, MessageLazy(false)
|
||||
, MessageNever(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.
|
||||
std::string install_always;
|
||||
if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
|
||||
this->Always = cmSystemTools::IsOn(install_always);
|
||||
}
|
||||
// Get the current manifest.
|
||||
this->Manifest =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
|
||||
}
|
||||
cmFileInstaller::~cmFileInstaller()
|
||||
{
|
||||
// Save the updated install manifest.
|
||||
this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
|
||||
this->Manifest.c_str());
|
||||
}
|
||||
|
||||
void cmFileInstaller::ManifestAppend(std::string const& file)
|
||||
{
|
||||
if (!this->Manifest.empty()) {
|
||||
this->Manifest += ";";
|
||||
}
|
||||
this->Manifest += file.substr(this->DestDirLength);
|
||||
}
|
||||
|
||||
std::string const& cmFileInstaller::ToName(std::string const& fromName)
|
||||
{
|
||||
return this->Rename.empty() ? fromName : this->Rename;
|
||||
}
|
||||
|
||||
void cmFileInstaller::ReportCopy(const std::string& toFile, Type type,
|
||||
bool copy)
|
||||
{
|
||||
if (!this->MessageNever && (copy || !this->MessageLazy)) {
|
||||
std::string message = (copy ? "Installing: " : "Up-to-date: ");
|
||||
message += toFile;
|
||||
this->Makefile->DisplayStatus(message, -1);
|
||||
}
|
||||
if (type != TypeDir) {
|
||||
// Add the file to the manifest.
|
||||
this->ManifestAppend(toFile);
|
||||
}
|
||||
}
|
||||
bool cmFileInstaller::ReportMissing(const std::string& fromFile)
|
||||
{
|
||||
return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
|
||||
}
|
||||
bool cmFileInstaller::Install(const std::string& fromFile,
|
||||
const std::string& toFile)
|
||||
{
|
||||
// Support installing from empty source to make a directory.
|
||||
if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
|
||||
return this->InstallDirectory(fromFile, toFile, MatchProperties());
|
||||
}
|
||||
return this->cmFileCopier::Install(fromFile, toFile);
|
||||
}
|
||||
|
||||
void cmFileInstaller::DefaultFilePermissions()
|
||||
{
|
||||
this->cmFileCopier::DefaultFilePermissions();
|
||||
// Add execute permissions based on the target type.
|
||||
switch (this->InstallType) {
|
||||
case cmInstallType_SHARED_LIBRARY:
|
||||
case cmInstallType_MODULE_LIBRARY:
|
||||
if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
|
||||
break;
|
||||
}
|
||||
CM_FALLTHROUGH;
|
||||
case cmInstallType_EXECUTABLE:
|
||||
case cmInstallType_PROGRAMS:
|
||||
this->FilePermissions |= mode_owner_execute;
|
||||
this->FilePermissions |= mode_group_execute;
|
||||
this->FilePermissions |= mode_world_execute;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool cmFileInstaller::Parse(std::vector<std::string> const& args)
|
||||
{
|
||||
if (!this->cmFileCopier::Parse(args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->Rename.empty()) {
|
||||
if (!this->FilesFromDir.empty()) {
|
||||
this->FileCommand->SetError("INSTALL option RENAME may not be "
|
||||
"combined with FILES_FROM_DIR.");
|
||||
return false;
|
||||
}
|
||||
if (this->InstallType != cmInstallType_FILES &&
|
||||
this->InstallType != cmInstallType_PROGRAMS) {
|
||||
this->FileCommand->SetError("INSTALL option RENAME may be used "
|
||||
"only with FILES or PROGRAMS.");
|
||||
return false;
|
||||
}
|
||||
if (this->Files.size() > 1) {
|
||||
this->FileCommand->SetError("INSTALL option RENAME may be used "
|
||||
"only with one file.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->HandleInstallDestination()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
|
||||
(this->MessageNever ? 1 : 0)) > 1) {
|
||||
this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
|
||||
"MESSAGE_LAZY, and MESSAGE_NEVER "
|
||||
"are mutually exclusive.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileInstaller::CheckKeyword(std::string const& arg)
|
||||
{
|
||||
if (arg == "TYPE") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingType;
|
||||
}
|
||||
} else if (arg == "FILES") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingFiles;
|
||||
}
|
||||
} else if (arg == "RENAME") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingRename;
|
||||
}
|
||||
} else if (arg == "OPTIONAL") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
this->Optional = true;
|
||||
}
|
||||
} else if (arg == "MESSAGE_ALWAYS") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
this->MessageAlways = true;
|
||||
}
|
||||
} else if (arg == "MESSAGE_LAZY") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
this->MessageLazy = true;
|
||||
}
|
||||
} else if (arg == "MESSAGE_NEVER") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
this->Doing = DoingNone;
|
||||
this->MessageNever = true;
|
||||
}
|
||||
} else if (arg == "PERMISSIONS") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->Doing = DoingPermissionsMatch;
|
||||
} else {
|
||||
// file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
|
||||
this->Doing = DoingPermissionsFile;
|
||||
this->UseGivenPermissionsFile = true;
|
||||
}
|
||||
} else if (arg == "DIR_PERMISSIONS") {
|
||||
if (this->CurrentMatchRule) {
|
||||
this->NotAfterMatch(arg);
|
||||
} else {
|
||||
// file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
|
||||
this->Doing = DoingPermissionsDir;
|
||||
this->UseGivenPermissionsDir = true;
|
||||
}
|
||||
} else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
|
||||
arg == "PROPERTIES") {
|
||||
std::ostringstream e;
|
||||
e << "INSTALL called with old-style " << arg << " argument. "
|
||||
<< "This script was generated with an older version of CMake. "
|
||||
<< "Re-run this cmake version on your build tree.";
|
||||
this->FileCommand->SetError(e.str());
|
||||
this->Doing = DoingError;
|
||||
} else {
|
||||
return this->cmFileCopier::CheckKeyword(arg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileInstaller::CheckValue(std::string const& arg)
|
||||
{
|
||||
switch (this->Doing) {
|
||||
case DoingType:
|
||||
if (!this->GetTargetTypeFromString(arg)) {
|
||||
this->Doing = DoingError;
|
||||
}
|
||||
break;
|
||||
case DoingRename:
|
||||
this->Rename = arg;
|
||||
break;
|
||||
default:
|
||||
return this->cmFileCopier::CheckValue(arg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
|
||||
{
|
||||
if (stype == "EXECUTABLE") {
|
||||
this->InstallType = cmInstallType_EXECUTABLE;
|
||||
} else if (stype == "FILE") {
|
||||
this->InstallType = cmInstallType_FILES;
|
||||
} else if (stype == "PROGRAM") {
|
||||
this->InstallType = cmInstallType_PROGRAMS;
|
||||
} else if (stype == "STATIC_LIBRARY") {
|
||||
this->InstallType = cmInstallType_STATIC_LIBRARY;
|
||||
} else if (stype == "SHARED_LIBRARY") {
|
||||
this->InstallType = cmInstallType_SHARED_LIBRARY;
|
||||
} else if (stype == "MODULE") {
|
||||
this->InstallType = cmInstallType_MODULE_LIBRARY;
|
||||
} else if (stype == "DIRECTORY") {
|
||||
this->InstallType = cmInstallType_DIRECTORY;
|
||||
} else {
|
||||
std::ostringstream e;
|
||||
e << "Option TYPE given unknown value \"" << stype << "\".";
|
||||
this->FileCommand->SetError(e.str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmFileInstaller::HandleInstallDestination()
|
||||
{
|
||||
std::string& destination = this->Destination;
|
||||
|
||||
// allow for / to be a valid destination
|
||||
if (destination.size() < 2 && destination != "/") {
|
||||
this->FileCommand->SetError("called with inappropriate arguments. "
|
||||
"No DESTINATION provided or .");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string sdestdir;
|
||||
if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
|
||||
cmSystemTools::ConvertToUnixSlashes(sdestdir);
|
||||
char ch1 = destination[0];
|
||||
char ch2 = destination[1];
|
||||
char ch3 = 0;
|
||||
if (destination.size() > 2) {
|
||||
ch3 = destination[2];
|
||||
}
|
||||
int skip = 0;
|
||||
if (ch1 != '/') {
|
||||
int relative = 0;
|
||||
if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
|
||||
ch2 == ':') {
|
||||
// Assume windows
|
||||
// let's do some destdir magic:
|
||||
skip = 2;
|
||||
if (ch3 != '/') {
|
||||
relative = 1;
|
||||
}
|
||||
} else {
|
||||
relative = 1;
|
||||
}
|
||||
if (relative) {
|
||||
// This is relative path on unix or windows. Since we are doing
|
||||
// destdir, this case does not make sense.
|
||||
this->FileCommand->SetError(
|
||||
"called with relative DESTINATION. This "
|
||||
"does not make sense when using DESTDIR. Specify "
|
||||
"absolute path or remove DESTDIR environment variable.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ch2 == '/') {
|
||||
// looks like a network path.
|
||||
std::string message =
|
||||
"called with network path DESTINATION. This "
|
||||
"does not make sense when using DESTDIR. Specify local "
|
||||
"absolute path or remove DESTDIR environment variable."
|
||||
"\nDESTINATION=\n";
|
||||
message += destination;
|
||||
this->FileCommand->SetError(message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
destination = sdestdir + (destination.c_str() + skip);
|
||||
this->DestDirLength = int(sdestdir.size());
|
||||
}
|
||||
|
||||
// check if default dir creation permissions were set
|
||||
mode_t default_dir_mode_v = 0;
|
||||
mode_t* default_dir_mode = &default_dir_mode_v;
|
||||
if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->InstallType != cmInstallType_DIRECTORY) {
|
||||
if (!cmSystemTools::FileExists(destination)) {
|
||||
if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
|
||||
std::string errstring = "cannot create directory: " + destination +
|
||||
". Maybe need administrative privileges.";
|
||||
this->FileCommand->SetError(errstring);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!cmSystemTools::FileIsDirectory(destination)) {
|
||||
std::string errstring =
|
||||
"INSTALL destination: " + destination + " is not a directory.";
|
||||
this->FileCommand->SetError(errstring);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
55
Source/cmFileInstaller.h
Normal file
55
Source/cmFileInstaller.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#ifndef cmFileInstaller_h
|
||||
#define cmFileInstaller_h
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmFileCopier.h"
|
||||
|
||||
#include "cmInstallType.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmFileCommand;
|
||||
|
||||
struct cmFileInstaller : public cmFileCopier
|
||||
{
|
||||
cmFileInstaller(cmFileCommand* command);
|
||||
~cmFileInstaller() override;
|
||||
|
||||
protected:
|
||||
cmInstallType InstallType;
|
||||
bool Optional;
|
||||
bool MessageAlways;
|
||||
bool MessageLazy;
|
||||
bool MessageNever;
|
||||
int DestDirLength;
|
||||
std::string Rename;
|
||||
|
||||
std::string Manifest;
|
||||
void ManifestAppend(std::string const& file);
|
||||
|
||||
std::string const& ToName(std::string const& fromName) override;
|
||||
|
||||
void ReportCopy(const std::string& toFile, Type type, bool copy) override;
|
||||
bool ReportMissing(const std::string& fromFile) override;
|
||||
bool Install(const std::string& fromFile,
|
||||
const std::string& toFile) override;
|
||||
|
||||
bool Parse(std::vector<std::string> const& args) override;
|
||||
enum
|
||||
{
|
||||
DoingType = DoingLast1,
|
||||
DoingRename,
|
||||
DoingLast2
|
||||
};
|
||||
bool CheckKeyword(std::string const& arg) override;
|
||||
bool CheckValue(std::string const& arg) override;
|
||||
void DefaultFilePermissions() override;
|
||||
bool GetTargetTypeFromString(const std::string& stype);
|
||||
bool HandleInstallDestination();
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user