BUG: stringOps etc expansion fails for directories (issue #1121)

- now use findEtcEntry() instead to handle file or directory.

  Added findEtcEntries(), which provides provides a common code basis
  for findEtcDirs(), findEtcFiles() ...
This commit is contained in:
Mark Olesen
2018-12-13 12:48:31 +01:00
parent 3d95f56589
commit 2db0db3006
8 changed files with 307 additions and 181 deletions

View File

@ -217,7 +217,7 @@ int main(int argc, char *argv[])
argList::addOption
(
"templateDir",
"file",
"dir",
"Read case set-up templates from specified location"
);
@ -238,25 +238,34 @@ int main(int argc, char *argv[])
)
);
// Template directory: default is from PROJECT/etc directory
//
// Can use
// - foamEtcDir("caseDicts/createZeroDirectory", 0007);
// - expand "<etc:o>/caseDicts/createZeroDirectory"
// - expand "${WM_PROJECT_DIR}/etc/caseDicts/createZeroDirectory"
//
// Use "${WM_PROJECT_DIR}/" version for nicer error message
fileName baseDir
(
args.opt<fileName>
(
"templateDir",
// Default is from PROJECT/etc directory
"<etc:o>/caseDicts/createZeroDirectoryTemplates"
"${WM_PROJECT_DIR}/etc/caseDicts/createZeroDirectoryTemplates"
)
);
baseDir.expand();
baseDir.toAbsolute();
if (!isDir(baseDir))
if (!Foam::isDir(baseDir))
{
FatalErrorInFunction
<< "templateDir " << baseDir
<< " should point to the folder containing the "
<< "case set-up templates" << exit(FatalError);
<< "templateDir " << baseDir << nl
<< "Does not point to a folder containing case set-up templates"
<< nl
<< exit(FatalError);
}
// Keep variable substitutions - delay until after creation of controlDict

View File

@ -205,7 +205,7 @@ do
-config)
optConfig=true
;;
-mode=[ugo]*)
-mode=[ugoa]*)
optMode="${1#*=}"
;;
-m | -mode)
@ -213,7 +213,7 @@ do
shift
# Sanity check. Handles missing argument too.
case "$optMode" in
([ugo]*)
([ugoa]*)
;;
(*)
die "invalid mode '$optMode'"
@ -290,17 +290,17 @@ fi
# Define the various places to be searched:
unset dirList
case "$optMode" in (*u*) # (U)ser
case "$optMode" in (*[au]*) # (A)ll or (U)ser
dirList="$dirList $userDir/$projectApi $userDir"
;;
esac
case "$optMode" in (*g*) # (G)roup == site
case "$optMode" in (*[ag]*) # (A)ll or (G)roup == site
dirList="$dirList $groupDir/$projectApi/etc $groupDir/etc"
;;
esac
case "$optMode" in (*o*) # (O)ther == shipped
case "$optMode" in (*[ao]*) # (A)ll or (O)ther == shipped
dirList="$dirList $projectDir/etc"
;;
esac

View File

@ -203,7 +203,7 @@ public:
// - $WM_PROJECT_DIR/etc/"caseDicts/postProcessing"
//
// Where {PROJECT_API} is the value of the OPENFOAM define.
// See further notes in Foam::findEtcFiles()
// See further notes in Foam::findEtcEntries()
static void list();
//- Find a functionObject dictionary file in the case

View File

@ -42,7 +42,6 @@ namespace
// - u : location mask 0700
// - g : location mask 0070
// - o : location mask 0007
//
static inline std::string locationToString(unsigned short location)
{
std::string mode;
@ -56,6 +55,27 @@ static inline std::string locationToString(unsigned short location)
}
// Error handling when a mandatory entry is not found
static inline void errorMandatoryNotFound
(
const std::string& name,
unsigned short location
)
{
// Abort when mandatory entry was not found.
// Use a direct exit, since this could occur before anything is
// setup at all.
std::cerr
<< "--> FOAM FATAL ERROR :\n "
"Could not find mandatory etc entry (mode="
<< locationToString(location) << ")\n '"
<< name << "'\n"
<< std::endl;
::exit(1);
}
// Assign 'queried' parameter to the user resource directory.
// Return true if this directory exists.
//
@ -141,91 +161,32 @@ static inline bool projectResourceDir(Foam::fileName& queried)
}
Foam::fileNameList searchEtc
// Check if the named file/directory matches the type required.
//
// - typeRequired (UNDEFINED) => accept either FILE or DIRECTORY
// - typeRequired (FILE | DIRECTORY) => accept only that type
static inline bool accept
(
const Foam::fileName& name,
unsigned short location,
const bool findFirst,
bool (*accept)(const Foam::fileName&)
const Foam::fileName::Type typeRequired
)
{
// Use foamVersion::api (instead of the OPENFOAM define) to ensure this
// stays properly synchronized with the build information
const Foam::fileName version(std::to_string(Foam::foamVersion::api));
// followLink(true), checkGzip(true)
// -> returns (UNDEFINED | FILE | DIRECTORY), no need to check for (LINK)
const auto t = name.type(true, true);
Foam::fileNameList list;
Foam::fileName queried, candidate;
if (!(location & 0777))
{
// Warn about bad location (mode) ... or make it FATAL?
std::cerr
<< "--> FOAM Error :\n "
"No user/group/other location specified for 'etc' file"
" or directory\n '"
<< name.c_str() << "'\n\n" << std::endl;
}
// User resource directories
if ((location & 0700) && userResourceDir(queried))
{
candidate = queried/version/name;
if (accept(candidate))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
candidate = queried/name;
if (accept(candidate))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
}
// Group (site) resource directories
if ((location & 0070) && groupResourceDir(queried))
{
candidate = queried/version/name;
if (accept(candidate))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
candidate = queried/name;
if (accept(candidate))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
}
// Other (project) resource directory
if ((location & 0007) && projectResourceDir(queried))
{
candidate = queried/name;
if (accept(candidate))
{
list.append(std::move(candidate));
}
}
return list;
return
(
// Found something?
Foam::fileName::Type::UNDEFINED != t
&&
(
// Any particular type required?
Foam::fileName::Type::UNDEFINED == typeRequired
? (Foam::fileName::Type::UNDEFINED != t)
: (typeRequired == t)
)
);
}
} // End anonymous namespace
@ -269,21 +230,115 @@ Foam::fileNameList Foam::etcDirs(bool test)
}
Foam::fileNameList Foam::findEtcEntries
(
const Foam::fileName& name,
unsigned short location,
const Foam::fileName::Type typeRequired,
const bool findFirst
)
{
// Debug Tracing
// std::cerr
// << "search ("<< locationToString(location) << "): "
// << name.c_str() << '\n';
if (!(location & 0777))
{
// Warn about bad location (mode) ... or make it FATAL?
std::cerr
<< "--> FOAM Error :\n "
"No user/group/other location specified for 'etc' file"
" or directory\n '"
<< name.c_str() << "'\n\n" << std::endl;
}
// Use foamVersion::api (instead of the OPENFOAM define) to ensure this
// stays properly synchronized with the build information
const Foam::fileName version(std::to_string(Foam::foamVersion::api));
Foam::fileNameList list;
Foam::fileName queried, candidate;
if (fileName::Type::FILE == typeRequired && name.empty())
{
// FILE must have a name to be found!
return list;
}
// User resource directories
if ((location & 0700) && userResourceDir(queried))
{
candidate = queried/version/name;
if (accept(candidate, typeRequired))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
candidate = queried/name;
if (accept(candidate, typeRequired))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
}
// Group (site) resource directories
if ((location & 0070) && groupResourceDir(queried))
{
candidate = queried/version/name;
if (accept(candidate, typeRequired))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
candidate = queried/name;
if (accept(candidate, typeRequired))
{
list.append(std::move(candidate));
if (findFirst)
{
return list;
}
}
}
// Other (project) resource directory
if ((location & 0007) && projectResourceDir(queried))
{
candidate = queried/name;
if (accept(candidate, typeRequired))
{
list.append(std::move(candidate));
}
}
return list;
}
Foam::fileNameList Foam::findEtcDirs
(
const fileName& name,
const bool findFirst,
unsigned short location
unsigned short location,
const bool findFirst
)
{
return
searchEtc
(
name,
location,
findFirst,
[](const fileName& f){ return Foam::isDir(f); }
);
return findEtcEntries(name, location, fileName::Type::DIRECTORY, findFirst);
}
@ -291,50 +346,34 @@ Foam::fileNameList Foam::findEtcFiles
(
const fileName& name,
const bool mandatory,
const bool findFirst,
unsigned short location
unsigned short location,
const bool findFirst
)
{
fileNameList list;
if (name.size())
{
// A file must have a name!
list = searchEtc
// Note: findEtcEntries checks name.size() for FILE
fileNameList list
(
name,
location,
findFirst,
[](const fileName& f){ return Foam::isFile(f); }
findEtcEntries(name, location, fileName::Type::FILE, findFirst)
);
}
if (mandatory && list.empty())
{
// Abort if file is mandatory but not found.
// Use a direct exit, since this could occur before anything is
// setup at all.
std::cerr
<< "--> FOAM FATAL ERROR :\n "
"Could not find mandatory etc file (mode="
<< locationToString(location) << ")\n '"
<< name.c_str() << "'\n"
<< std::endl;
::exit(1);
errorMandatoryNotFound(name, location);
}
return list;
}
Foam::fileName Foam::findEtcDir
Foam::fileName Foam::findEtcEntry
(
const fileName& name,
unsigned short location
unsigned short location,
const Foam::fileName::Type typeRequired
)
{
fileNameList list(findEtcDirs(name, true, location));
// With findFirst(true)
fileNameList list(findEtcEntries(name, location, typeRequired, true));
fileName found;
@ -347,6 +386,16 @@ Foam::fileName Foam::findEtcDir
}
Foam::fileName Foam::findEtcDir
(
const fileName& name,
unsigned short location
)
{
return findEtcEntry(name, location, fileName::Type::DIRECTORY);
}
Foam::fileName Foam::findEtcFile
(
const fileName& name,
@ -354,13 +403,11 @@ Foam::fileName Foam::findEtcFile
unsigned short location
)
{
fileNameList list(findEtcFiles(name, mandatory, true, location));
fileName found(findEtcEntry(name, location, fileName::Type::FILE));
fileName found;
if (list.size())
if (mandatory && found.empty())
{
found = std::move(list.first());
errorMandatoryNotFound(name, location);
}
return found;

View File

@ -52,30 +52,7 @@ namespace Foam
fileNameList etcDirs(bool test=true);
//- Search for directories from user/group/other directories.
// Uses search hierarchy as per findEtcFiles().
//
// \return The list of full paths of all the matching directories or
// an empty list if the name cannot be found.
fileNameList findEtcDirs
(
const fileName& name, //!< The directory to search for
const bool findFirst=false, //!< Stop after locating the first directory
unsigned short location=0777 //!< User/group/other location
);
//- Search for a single directory using findEtcDirs().
//
// \return The full path name of the first directory found in the
// search hierarchy or an empty fileName if the name cannot be found.
fileName findEtcDir
(
const fileName& name, //!< The directory to search for
unsigned short location=0777 //!< User/group/other location
);
//- Search for files from user/group/other directories.
//- Search for files or directories from user/group/other etc locations.
//
// The search hierarchy corresponds to that of the \c foamEtcFile script,
// which allows for version-specific and version-independent files.
@ -90,24 +67,115 @@ fileName findEtcDir
// - $WM_PROJECT_DIR/etc/
//
// Where {PROJECT_API} corresponds to the foamVersion::api value.
// When \c \$WM_PROJECT_SITE is unset, uses \c $WM_PROJECT_DIR/site
//
// \note When \c \$WM_PROJECT_SITE is unset, uses \c $WM_PROJECT_DIR/site
// \param name The entry to search for. For a FILE search,
// this should be non-empty. For a DIRECTORY search or a general
// (UNDEFINED) search, this can be an empty string.
// \param location The search locations as a numerical mode.
// The default (0777) searches user/group/other locations.
// \param typeRequired restricts the search to the specified type.
// The default (UNDEFINED) accepts FILE or DIRECTORY entries.
// \param findFirst Optionally stop after locating the first entry.
//
// \return The list of full paths of all the matching files or directories
// or an empty list if the name cannot be resolved.
fileNameList findEtcEntries
(
const fileName& name,
unsigned short location=0777,
const fileName::Type typeRequired = fileName::Type::UNDEFINED,
const bool findFirst=false
);
//- Search for directories from user/group/other etc locations.
// The search hierarchy corresponds to that of the \c foamEtcFile script,
// which allows for version-specific and version-independent files.
//
// This function corresponds to using Foam::findEtcEntries()
// with (DIRECTORY) for the type required.
//
// \param name The directory to search for. This can be an empty string.
// \param location The search locations as a numerical mode.
// The default (0777) searches user/group/other locations.
// \param findFirst Optionally stop after locating the first entry.
//
// \return The list of full paths of all the matching directories or
// an empty list if the name cannot be found.
fileNameList findEtcDirs
(
const fileName& name,
unsigned short location=0777,
const bool findFirst=false
);
//- Search for files from user/group/other etc locations.
// The search hierarchy corresponds to that of the \c foamEtcFile script,
// which allows for version-specific and version-independent files.
//
// This function corresponds to using Foam::findEtcEntries()
// with (FILE) for the type required, but has an additional
// check for mandatory files.
//
// \param name The file to search for. If this is an empty string,
// nothing will be matched.
// \param mandatory Abort if the mandatory file cannot be found.
// \param location The search locations as a numerical mode.
// The default (0777) searches user/group/other locations.
// \param findFirst Optionally stop after locating the first entry.
//
// \return The list of full paths of all the matching files or
// an empty list if the name cannot be found.
fileNameList findEtcFiles
(
const fileName& name, //!< The file to search for
const bool mandatory=false, //!< Abort if the file cannot be found
const bool findFirst=false, //!< Stop after locating the first directory
unsigned short location=0777 //!< User/group/other location
const fileName& name,
const bool mandatory=false,
unsigned short location=0777,
const bool findFirst=false
);
//- Search for a single file using findEtcFiles().
//- Search for a single FILE or DIRECTORY within the etc directories
//
// \param name The entry to search for. For a FILE search,
// this should be non-empty. For a DIRECTORY search or a general
// (UNDEFINED) search, this can be an empty string.
// \param location The search locations as a numerical mode.
// The default (0777) searches user/group/other locations.
// \param typeRequired restricts the search to the specified type.
// The default (UNDEFINED) accepts FILE or DIRECTORY entries.
//
// \return The full path name of the first entry found in the
// search hierarchy or an empty fileName if the name cannot be found.
//
// \sa Foam::findEtcEntries()
fileName findEtcEntry
(
const fileName& name,
unsigned short location=0777,
const fileName::Type typeRequired = fileName::Type::UNDEFINED
);
//- Search for a single FILE within the etc directories
//
// \return The full path name of the first directory found in the
// search hierarchy or an empty fileName if the name cannot be found.
//
// \sa Foam::findEtcEntries(), Foam::findEtcDirs()
fileName findEtcDir
(
const fileName& name, //!< The directory to search for
unsigned short location=0777 //!< User/group/other location
);
//- Search for a single FILE within the etc directories
//
// \return The full path name of the first file found in the
// search hierarchy or an empty fileName if the name cannot be found.
//
// \sa Foam::findEtcEntries(), Foam::findEtcFiles()
fileName findEtcFile
(
const fileName& name, //!< The file to search for

View File

@ -58,7 +58,7 @@ void Foam::cellModel::constructModels()
<< exit(FatalError);
}
IFstream is(findEtcFile("cellModels", true));
IFstream is(findEtcFile("cellModels", true)); // Mandatory file
PtrList<cellModel> newPtrs(is);
models_.swap(newPtrs);

View File

@ -42,6 +42,7 @@ namespace Foam
// - u : location mask 0700
// - g : location mask 0070
// - o : location mask 0007
// - a : location mask 0777
//
static inline unsigned short modeToLocation
(
@ -54,6 +55,7 @@ static inline unsigned short modeToLocation
if (std::string::npos != mode.find('u', pos)) { where |= 0700; } // User
if (std::string::npos != mode.find('g', pos)) { where |= 0070; } // Group
if (std::string::npos != mode.find('o', pos)) { where |= 0007; } // Other
if (std::string::npos != mode.find('a', pos)) { where |= 0777; } // All
return where;
}
@ -62,8 +64,8 @@ static inline unsigned short modeToLocation
// Expand a leading <tag>/
// Convenient for frequently used directories
//
// <etc>/ => user/group/other etc - findEtcFile()
// <etc(:[ugo]+)?>/ => user/group/other etc - findEtcFile()
// <etc>/ => user/group/other etc - findEtcEntry()
// <etc(:[ugoa]+)?>/ => user/group/other etc - findEtcEntry()
// <case>/ => FOAM_CASE directory
// <constant>/ => FOAM_CASE/constant directory
// <system>/ => FOAM_CASE/system directory
@ -102,7 +104,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
if (tag == "etc")
{
s = findEtcFile(file);
s = findEtcEntry(file);
}
else if (tag == "case")
{
@ -114,9 +116,9 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
}
else if (tagLen >= 4 && tag.compare(0, 4, "etc:") == 0)
{
// <etc:ugo> type of tag - convert "ugo" to numeric
// <etc:[ugoa]+> type of tag - convert "ugo" to numeric
s = findEtcFile(file, false, modeToLocation(tag, 4));
s = findEtcEntry(file, modeToLocation(tag,4));
}
}

View File

@ -224,7 +224,7 @@ namespace stringOps
// -# leading tag expansion for commonly used directories
// - <b> \<etc\>/ </b>
// : user/group/other OpenFOAM etc directory
// - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b>
// - <b> \<etc:</b><em>[ugoa]+</em>)<b>\>/ </b>
// : user/group/other etc with specified location mode
// - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory
@ -263,7 +263,7 @@ namespace stringOps
// "~OpenFOAM" expansion
//
// \sa
// Foam::findEtcFile
// Foam::findEtcEntry(), Foam::findEtcEntries(),
string expand
(
const string& original,
@ -280,7 +280,7 @@ namespace stringOps
// -# leading tag expansion for commonly used directories
// - <b> \<etc\>/ </b>
// : user/group/other OpenFOAM etc directory
// - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b>
// - <b> \<etc:</b><em>[ugoa]+</em>)<b>\>/ </b>
// : user/group/other etc with specified location mode
// - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory
@ -312,7 +312,7 @@ namespace stringOps
// "~OpenFOAM" expansion
//
// \sa
// Foam::findEtcFile
// Foam::findEtcEntry(), Foam::findEtcEntries(),
void inplaceExpand
(
std::string& s,