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 argList::addOption
( (
"templateDir", "templateDir",
"file", "dir",
"Read case set-up templates from specified location" "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 fileName baseDir
( (
args.opt<fileName> args.opt<fileName>
( (
"templateDir", "templateDir",
// Default is from PROJECT/etc directory "${WM_PROJECT_DIR}/etc/caseDicts/createZeroDirectoryTemplates"
"<etc:o>/caseDicts/createZeroDirectoryTemplates"
) )
); );
baseDir.expand(); baseDir.expand();
baseDir.toAbsolute(); baseDir.toAbsolute();
if (!isDir(baseDir)) if (!Foam::isDir(baseDir))
{ {
FatalErrorInFunction FatalErrorInFunction
<< "templateDir " << baseDir << "templateDir " << baseDir << nl
<< " should point to the folder containing the " << "Does not point to a folder containing case set-up templates"
<< "case set-up templates" << exit(FatalError); << nl
<< exit(FatalError);
} }
// Keep variable substitutions - delay until after creation of controlDict // Keep variable substitutions - delay until after creation of controlDict

View File

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

View File

@ -203,7 +203,7 @@ public:
// - $WM_PROJECT_DIR/etc/"caseDicts/postProcessing" // - $WM_PROJECT_DIR/etc/"caseDicts/postProcessing"
// //
// Where {PROJECT_API} is the value of the OPENFOAM define. // 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(); static void list();
//- Find a functionObject dictionary file in the case //- Find a functionObject dictionary file in the case

View File

@ -42,7 +42,6 @@ namespace
// - u : location mask 0700 // - u : location mask 0700
// - g : location mask 0070 // - g : location mask 0070
// - o : location mask 0007 // - o : location mask 0007
//
static inline std::string locationToString(unsigned short location) static inline std::string locationToString(unsigned short location)
{ {
std::string mode; 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. // Assign 'queried' parameter to the user resource directory.
// Return true if this directory exists. // 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, const Foam::fileName& name,
unsigned short location, const Foam::fileName::Type typeRequired
const bool findFirst,
bool (*accept)(const Foam::fileName&)
) )
{ {
// Use foamVersion::api (instead of the OPENFOAM define) to ensure this // followLink(true), checkGzip(true)
// stays properly synchronized with the build information // -> returns (UNDEFINED | FILE | DIRECTORY), no need to check for (LINK)
const Foam::fileName version(std::to_string(Foam::foamVersion::api)); const auto t = name.type(true, true);
Foam::fileNameList list; return
Foam::fileName queried, candidate; (
// Found something?
if (!(location & 0777)) Foam::fileName::Type::UNDEFINED != t
{ &&
// Warn about bad location (mode) ... or make it FATAL? (
std::cerr // Any particular type required?
<< "--> FOAM Error :\n " Foam::fileName::Type::UNDEFINED == typeRequired
"No user/group/other location specified for 'etc' file" ? (Foam::fileName::Type::UNDEFINED != t)
" or directory\n '" : (typeRequired == t)
<< 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;
} }
} // End anonymous namespace } // 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 Foam::fileNameList Foam::findEtcDirs
( (
const fileName& name, const fileName& name,
const bool findFirst, unsigned short location,
unsigned short location const bool findFirst
) )
{ {
return return findEtcEntries(name, location, fileName::Type::DIRECTORY, findFirst);
searchEtc
(
name,
location,
findFirst,
[](const fileName& f){ return Foam::isDir(f); }
);
} }
@ -291,50 +346,34 @@ Foam::fileNameList Foam::findEtcFiles
( (
const fileName& name, const fileName& name,
const bool mandatory, const bool mandatory,
const bool findFirst, unsigned short location,
unsigned short location const bool findFirst
) )
{ {
fileNameList list; // Note: findEtcEntries checks name.size() for FILE
fileNameList list
if (name.size()) (
{ findEtcEntries(name, location, fileName::Type::FILE, findFirst)
// A file must have a name! );
list = searchEtc
(
name,
location,
findFirst,
[](const fileName& f){ return Foam::isFile(f); }
);
}
if (mandatory && list.empty()) if (mandatory && list.empty())
{ {
// Abort if file is mandatory but not found. errorMandatoryNotFound(name, location);
// 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);
} }
return list; return list;
} }
Foam::fileName Foam::findEtcDir Foam::fileName Foam::findEtcEntry
( (
const fileName& name, 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; 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 Foam::fileName Foam::findEtcFile
( (
const fileName& name, const fileName& name,
@ -354,13 +403,11 @@ Foam::fileName Foam::findEtcFile
unsigned short location unsigned short location
) )
{ {
fileNameList list(findEtcFiles(name, mandatory, true, location)); fileName found(findEtcEntry(name, location, fileName::Type::FILE));
fileName found; if (mandatory && found.empty())
if (list.size())
{ {
found = std::move(list.first()); errorMandatoryNotFound(name, location);
} }
return found; return found;

View File

@ -52,30 +52,7 @@ namespace Foam
fileNameList etcDirs(bool test=true); fileNameList etcDirs(bool test=true);
//- Search for directories from user/group/other directories. //- Search for files or directories from user/group/other etc locations.
// 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.
// //
// The search hierarchy corresponds to that of the \c foamEtcFile script, // The search hierarchy corresponds to that of the \c foamEtcFile script,
// which allows for version-specific and version-independent files. // which allows for version-specific and version-independent files.
@ -90,29 +67,120 @@ fileName findEtcDir
// - $WM_PROJECT_DIR/etc/ // - $WM_PROJECT_DIR/etc/
// //
// Where {PROJECT_API} corresponds to the foamVersion::api value. // 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 // \return The list of full paths of all the matching files or
// an empty list if the name cannot be found. // an empty list if the name cannot be found.
fileNameList findEtcFiles fileNameList findEtcFiles
( (
const fileName& name, //!< The file to search for const fileName& name,
const bool mandatory=false, //!< Abort if the file cannot be found const bool mandatory=false,
const bool findFirst=false, //!< Stop after locating the first directory unsigned short location=0777,
unsigned short location=0777 //!< User/group/other location 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 // \return The full path name of the first file found in the
// search hierarchy or an empty fileName if the name cannot be found. // search hierarchy or an empty fileName if the name cannot be found.
//
// \sa Foam::findEtcEntries(), Foam::findEtcFiles()
fileName findEtcFile fileName findEtcFile
( (
const fileName& name, //!< The file to search for const fileName& name, //!< The file to search for
const bool mandatory=false, //!< Abort if the file cannot be found const bool mandatory=false, //!< Abort if the file cannot be found
unsigned short location=0777 //!< User/group/other location unsigned short location=0777 //!< User/group/other location
); );

View File

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

View File

@ -42,6 +42,7 @@ namespace Foam
// - u : location mask 0700 // - u : location mask 0700
// - g : location mask 0070 // - g : location mask 0070
// - o : location mask 0007 // - o : location mask 0007
// - a : location mask 0777
// //
static inline unsigned short modeToLocation 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('u', pos)) { where |= 0700; } // User
if (std::string::npos != mode.find('g', pos)) { where |= 0070; } // Group 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('o', pos)) { where |= 0007; } // Other
if (std::string::npos != mode.find('a', pos)) { where |= 0777; } // All
return where; return where;
} }
@ -62,8 +64,8 @@ static inline unsigned short modeToLocation
// Expand a leading <tag>/ // Expand a leading <tag>/
// Convenient for frequently used directories // Convenient for frequently used directories
// //
// <etc>/ => user/group/other etc - findEtcFile() // <etc>/ => user/group/other etc - findEtcEntry()
// <etc(:[ugo]+)?>/ => user/group/other etc - findEtcFile() // <etc(:[ugoa]+)?>/ => user/group/other etc - findEtcEntry()
// <case>/ => FOAM_CASE directory // <case>/ => FOAM_CASE directory
// <constant>/ => FOAM_CASE/constant directory // <constant>/ => FOAM_CASE/constant directory
// <system>/ => FOAM_CASE/system 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") if (tag == "etc")
{ {
s = findEtcFile(file); s = findEtcEntry(file);
} }
else if (tag == "case") 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) 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 // -# leading tag expansion for commonly used directories
// - <b> \<etc\>/ </b> // - <b> \<etc\>/ </b>
// : user/group/other OpenFOAM etc directory // : 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 // : user/group/other etc with specified location mode
// - <b> \<case\>/ </b> // - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory // : The \c $FOAM_CASE directory
@ -263,7 +263,7 @@ namespace stringOps
// "~OpenFOAM" expansion // "~OpenFOAM" expansion
// //
// \sa // \sa
// Foam::findEtcFile // Foam::findEtcEntry(), Foam::findEtcEntries(),
string expand string expand
( (
const string& original, const string& original,
@ -280,7 +280,7 @@ namespace stringOps
// -# leading tag expansion for commonly used directories // -# leading tag expansion for commonly used directories
// - <b> \<etc\>/ </b> // - <b> \<etc\>/ </b>
// : user/group/other OpenFOAM etc directory // : 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 // : user/group/other etc with specified location mode
// - <b> \<case\>/ </b> // - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory // : The \c $FOAM_CASE directory
@ -312,7 +312,7 @@ namespace stringOps
// "~OpenFOAM" expansion // "~OpenFOAM" expansion
// //
// \sa // \sa
// Foam::findEtcFile // Foam::findEtcEntry(), Foam::findEtcEntries(),
void inplaceExpand void inplaceExpand
( (
std::string& s, std::string& s,