53 bool FileExists(
const string& filename,
bool directory =
false)
56 if (stat(filename.c_str(), &s) == 0)
57 return directory ? S_ISDIR(s.st_mode) : S_ISREG(s.st_mode);
66 #if defined(__DARWIN_UNIX03)
72 static const char* dirname(
const char *filename)
74 return ::dirname(const_cast<char*>(filename));
78 static const char PathDelimiter =
':';
83 bool fabrique::PathIsAbsolute(
const string& path)
85 return (not path.empty() and path[0] ==
'/');
89 string fabrique::AbsoluteDirectory(
string name,
bool createIfMissing)
91 const char *cname = name.c_str();
94 if (stat(cname, &s) != 0)
96 if (errno == ENOENT and createIfMissing)
98 if (mkdir(cname, 0777) != 0)
99 throw PosixError(
"creating directory " + name);
102 throw PosixError(
"reading directory " + name);
105 return AbsolutePath(cname);
109 string fabrique::AbsolutePath(
string name)
111 char *absolutePath = realpath(name.c_str(),
nullptr);
112 if (not absolutePath)
113 throw PosixError(
"error in realpath('" + name +
"')");
115 string path(absolutePath);
125 string fabrique::BaseName(
string path)
127 const string filename = FilenameComponent(path);
128 return filename.substr(0, filename.rfind(
'.'));
132 string fabrique::CreateDirCommand(
string dir)
134 return "if [ ! -e \"" + dir +
"\" ]; then mkdir -p \"" + dir +
"\"; fi";
138 fabrique::MissingFileReporter fabrique::DefaultFilename(std::string name)
140 return [name](string,
const vector<string>&) {
return name; };
144 string fabrique::DirectoryOf(
string filename,
bool absolute)
146 const char *dir = dirname(filename.c_str());
149 throw PosixError(
"error looking for parent of " + filename);
151 const string relative(dir);
153 return (relative ==
".") ?
"" : relative;
155 const string absoluteDir(AbsoluteDirectory(dir));
158 if (stat(absoluteDir.c_str(), &s) != 0)
159 throw PosixError(
"error querying " + absoluteDir);
161 if (not S_ISDIR(s.st_mode))
162 throw PosixError(filename +
" is not a directory");
168 string fabrique::FileExtension(
string path)
170 const string filename = FilenameComponent(path);
172 size_t i = filename.rfind(
'.');
173 if (i == string::npos)
177 return filename.substr(i + 1);
181 bool fabrique::FileIsExecutable(
string path)
184 if (stat(path.c_str(), &s) != 0)
185 throw PosixError(
"error querying '" + path +
"'");
187 if (not S_ISREG(s.st_mode))
190 return (s.st_mode & S_IXUSR);
194 bool fabrique::FileIsSharedLibrary(
string path)
201 if (stat(path.c_str(), &s) != 0)
202 throw PosixError(
"error querying '" + path +
"'");
204 if (not S_ISREG(s.st_mode))
207 return (s.st_mode & S_IXUSR);
211 string fabrique::FilenameComponent(
string pathIncludingDirectory)
213 if (pathIncludingDirectory.empty())
216 const char *cname = pathIncludingDirectory.c_str();
217 return basename(const_cast<char*>(cname));
221 string fabrique::FileNotFound(
string name,
const vector<string>& searchPaths)
223 std::ostringstream oss;
224 oss <<
"no file '" << name <<
"' in directories [";
226 for (
const string& directory : searchPaths)
227 oss <<
" '" << directory <<
"'";
231 throw UserError(oss.str());
235 string fabrique::FindExecutable(
string name, MissingFileReporter report)
237 const char *path = getenv(
"PATH");
239 throw PosixError(
"error in getenv('PATH')");
241 return FindFile(name, Split(path, PathDelimiter), FileIsExecutable, report);
245 string fabrique::FindFile(
string filename,
const vector<string>& directories,
246 std::function<
bool (
const string&)> test,
247 MissingFileReporter fileNotFound)
249 for (
const string& directory : directories)
251 const string absolute = JoinPath(directory, filename);
252 if (PathIsFile(absolute) and test(absolute))
256 return fileNotFound(filename, directories);
260 string fabrique::FindModule(
string srcroot,
string subdir,
string name)
262 const string relativeName = JoinPath(subdir, name);
267 if (PathIsAbsolute(relativeName) and FileExists(relativeName))
276 if (FileExists(JoinPath(srcroot, relativeName)))
282 const vector<string> searchPaths = {
283 "/usr/local/share/fabrique",
286 const string found = FindFile(relativeName, searchPaths,
287 PathIsFile, DefaultFilename(
""));
288 if (not found.empty())
294 const string dirname = JoinPath(srcroot, relativeName);
295 if (FileExists(dirname,
true))
297 const string fabfile = JoinPath(dirname,
"fabfile");
298 if (FileExists(fabfile))
299 return JoinPath(relativeName,
"fabfile");
302 throw UserError(
"unable to find module '" + name +
"'");
306 string fabrique::JoinPath(
const string& x,
const string& y)
308 if (x.empty() or x ==
".")
311 if (y.empty() or y ==
".")
317 string fabrique::JoinPath(
const vector<string>& components)
319 return join(components,
"/");
323 string fabrique::LibraryFilename(
string name)
325 static constexpr
char Extension[] =
333 return "lib" + name +
"." + Extension;
337 vector<string> fabrique::PluginSearchPaths(
string binary)
339 const string prefix = DirectoryOf(DirectoryOf(binary));
341 prefix +
"/lib/fabrique",
343 "/usr/local/lib/fabrique",
348 bool fabrique::PathIsDirectory(
string path)
350 return FileExists(path,
true);
353 bool fabrique::PathIsFile(
string path)
355 return FileExists(path,
false);
Declaration of fabrique::PosixError.
An OS error that has an errno or equivalent output.
Declaration of basic Fabrique exceptions.
Declarations of OS-abstraction functions.
Declaration of the fabrique::Join ostream helper and some helper functions for joining strings (or th...
Declaration of string utility functions.
Declaration of fabrique::Bytestream.