summaryrefslogtreecommitdiffstats
path: root/Source/cmFileCommand.cxx
diff options
context:
space:
mode:
authorRuslan Baratov <ruslan_baratov@yahoo.com>2014-11-25 22:49:25 (GMT)
committerBrad King <brad.king@kitware.com>2014-12-03 14:47:44 (GMT)
commite6db4c5a4ede8039ed525e3facebd7e0eb7ec1b7 (patch)
treef5e6a3dce7b89725f9fa4e5fcafd040114a85466 /Source/cmFileCommand.cxx
parent05d6531c7a8ecfad513a0e76b44b273b70fa919b (diff)
downloadCMake-e6db4c5a4ede8039ed525e3facebd7e0eb7ec1b7.zip
CMake-e6db4c5a4ede8039ed525e3facebd7e0eb7ec1b7.tar.gz
CMake-e6db4c5a4ede8039ed525e3facebd7e0eb7ec1b7.tar.bz2
file: Add LOCK subcommand to do file and directory locking
Provide options to fail without blocking or to block up to a timeout. Provide options to specify the scope containing the lock so it can be released automatically at the end of a function, file, or process. Extend the RunCMake.file test with cases covering the file(LOCK) command usage and error cases.
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r--Source/cmFileCommand.cxx203
1 files changed, 203 insertions, 0 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index aa4c95b..a6eb8c4 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -21,6 +21,7 @@
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_curl.h"
+#include "cmFileLockResult.h"
#endif
#undef GetCurrentDirectory
@@ -202,6 +203,10 @@ bool cmFileCommand
{
return this->HandleGenerateCommand(args);
}
+ else if ( subCommand == "LOCK" )
+ {
+ return this->HandleLockCommand(args);
+ }
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e);
@@ -3502,6 +3507,204 @@ bool cmFileCommand::HandleGenerateCommand(
}
//----------------------------------------------------------------------------
+bool cmFileCommand::HandleLockCommand(
+ std::vector<std::string> const& args)
+{
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+ // Default values
+ bool directory = false;
+ bool release = false;
+ enum Guard {
+ GUARD_FUNCTION,
+ GUARD_FILE,
+ GUARD_PROCESS
+ };
+ Guard guard = GUARD_PROCESS;
+ std::string resultVariable;
+ unsigned timeout = static_cast<unsigned>(-1);
+
+ // Parse arguments
+ if(args.size() < 2)
+ {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "sub-command LOCK requires at least two arguments.");
+ return false;
+ }
+
+ std::string path = args[1];
+ for (unsigned i = 2; i < args.size(); ++i)
+ {
+ if (args[i] == "DIRECTORY")
+ {
+ directory = true;
+ }
+ else if (args[i] == "RELEASE")
+ {
+ release = true;
+ }
+ else if (args[i] == "GUARD")
+ {
+ ++i;
+ const char* merr = "expected FUNCTION, FILE or PROCESS after GUARD";
+ if (i >= args.size())
+ {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, merr);
+ return false;
+ }
+ else
+ {
+ if (args[i] == "FUNCTION")
+ {
+ guard = GUARD_FUNCTION;
+ }
+ else if (args[i] == "FILE")
+ {
+ guard = GUARD_FILE;
+ }
+ else if (args[i] == "PROCESS")
+ {
+ guard = GUARD_PROCESS;
+ }
+ else
+ {
+ cmOStringStream e;
+ e << merr << ", but got:\n \"" << args[i] << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+ }
+ else if (args[i] == "RESULT_VARIABLE")
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "expected variable name after RESULT_VARIABLE");
+ return false;
+ }
+ resultVariable = args[i];
+ }
+ else if (args[i] == "TIMEOUT")
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ this->Makefile->IssueMessage(
+ cmake::FATAL_ERROR,
+ "expected timeout value after TIMEOUT");
+ return false;
+ }
+ int scanned;
+ if(!cmSystemTools::StringToInt(args[i].c_str(), &scanned) || scanned < 0)
+ {
+ cmOStringStream e;
+ e << "TIMEOUT value \"" << args[i] << "\" is not an unsigned integer.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ timeout = static_cast<unsigned>(scanned);
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "expected DIRECTORY, RELEASE, GUARD, RESULT_VARIABLE or TIMEOUT\n";
+ e << "but got: \"" << args[i] << "\".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ if (directory)
+ {
+ path += "/cmake.lock";
+ }
+
+ if (!cmsys::SystemTools::FileIsFullPath(path))
+ {
+ path = this->Makefile->GetCurrentDirectory() + ("/" + path);
+ }
+
+ // Unify path (remove '//', '/../', ...)
+ path = cmSystemTools::CollapseFullPath(path);
+
+ // Create file and directories if needed
+ std::string parentDir = cmSystemTools::GetParentDirectory(path);
+ if (!cmSystemTools::MakeDirectory(parentDir))
+ {
+ cmOStringStream e;
+ e << "directory\n \"" << parentDir << "\"\ncreation failed ";
+ e << "(check permissions).";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ FILE *file = cmsys::SystemTools::Fopen(path, "w");
+ if (!file)
+ {
+ cmOStringStream e;
+ e << "file\n \"" << path << "\"\ncreation failed (check permissions).";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ fclose(file);
+
+ // Actual lock/unlock
+ cmFileLockPool& lockPool = this->Makefile->GetLocalGenerator()->
+ GetGlobalGenerator()->GetFileLockPool();
+
+ cmFileLockResult fileLockResult(cmFileLockResult::MakeOk());
+ if (release)
+ {
+ fileLockResult = lockPool.Release(path);
+ }
+ else
+ {
+ switch (guard)
+ {
+ case GUARD_FUNCTION:
+ fileLockResult = lockPool.LockFunctionScope(path, timeout);
+ break;
+ case GUARD_FILE:
+ fileLockResult = lockPool.LockFileScope(path, timeout);
+ break;
+ case GUARD_PROCESS:
+ fileLockResult = lockPool.LockProcessScope(path, timeout);
+ break;
+ default:
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ const std::string result = fileLockResult.GetOutputMessage();
+
+ if (resultVariable.empty() && !fileLockResult.IsOk())
+ {
+ cmOStringStream e;
+ e << "error locking file\n \"" << path << "\"\n" << result << ".";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!resultVariable.empty())
+ {
+ this->Makefile->AddDefinition(resultVariable, result.c_str());
+ }
+
+ return true;
+#else
+ static_cast<void>(args);
+ this->SetError("sub-command LOCK not implemented in bootstrap cmake");
+ return false;
+#endif
+}
+
+//----------------------------------------------------------------------------
bool cmFileCommand::HandleTimestampCommand(
std::vector<std::string> const& args)
{