ENH: support search modes for etcFiles()

- similar to the foamEtcFile script -mode=... option, the specific
  search location (user/group/other) can now also specified for
  string expansions and as a numerical value for etcFile()

  For example, if searching for group or other (project) controlDict,
  but not wishing to see the user controlDict:

    1.  foamEtcFile -mode=go controlDict

    2.  fileName dictFile("<etc:go>/controlDict");
        dictFile.expand();

    3.  etcFile(controlDict, false, 0077);

  The default behaviour for searching all contexts is unchanged.

    1.  foamEtcFile controlDict

    2.  fileName dictFile("<etc>/controlDict");
        dictFile.expand();

    3.  etcFile(controlDict);
This commit is contained in:
Mark Olesen
2018-12-12 13:45:32 +01:00
parent 67140f6b07
commit 172c36c29a
7 changed files with 220 additions and 71 deletions

View File

@ -102,6 +102,12 @@ int main(int argc, char *argv[])
} }
} }
// This should and will fail:
//// Info<<"find bad file:" << nl
//// << findEtcFile("##BadName##", true) << "FAIL" << endl;
const bool listAll = (args.found("all") || args.found("list")); const bool listAll = (args.found("all") || args.found("list"));
int error = 0; int error = 0;

View File

@ -102,6 +102,13 @@ int main(int argc, char *argv[])
: :
{ {
"~OpenFOAM/controlDict", "<etc>/controlDict", "~OpenFOAM/controlDict", "<etc>/controlDict",
"<etc:ugo>/controlDict",
"<etc:u>/controlDict",
"<etc:ug>/controlDict",
"<etc:go>/controlDict",
"<etc:o>/controlDict",
"<etc:JUNK>/controlDict", // rubbish input
"<etc:>/controlDict", // rubbish input
"$FOAM_CASE/xyz", "<case>/xyz", "$FOAM_CASE/xyz", "<case>/xyz",
"$FOAM_CASE/constant/xyz", "<constant>/xyz", "$FOAM_CASE/constant/xyz", "<constant>/xyz",
"$FOAM_CASE/system/xyz", "<system>/xyz", "$FOAM_CASE/system/xyz", "<system>/xyz",

View File

@ -240,12 +240,13 @@ int main(int argc, char *argv[])
fileName baseDir fileName baseDir
( (
"${WM_PROJECT_DIR}/etc/caseDicts/createZeroDirectoryTemplates" args.opt<fileName>
(
"templateDir",
// Default is from PROJECT/etc directory
"<etc:o>/caseDicts/createZeroDirectoryTemplates"
)
); );
if (args.found("templateDir"))
{
baseDir = args["templateDir"];
}
baseDir.expand(); baseDir.expand();
baseDir.toAbsolute(); baseDir.toAbsolute();

View File

@ -30,12 +30,32 @@ License
// * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * * //
// //
// These could be exposed too (if required), but are fairly special purpose. // Some of these could be exposed too (if required),
// but are fairly special purpose.
// //
namespace namespace
{ {
// Return the file location mode as a string.
//
// - u : location mask 0700
// - g : location mask 0070
// - o : location mask 0007
//
static inline std::string locationToString(unsigned short location)
{
std::string mode;
if (location & 0700) { mode += 'u'; } // User
if (location & 0070) { mode += 'g'; } // Group
if (location & 0007) { mode += 'o'; } // Other
if (mode.empty()) { mode = "???"; }
return mode;
}
// 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.
// //
@ -64,6 +84,7 @@ static inline bool userResourceDir(Foam::fileName& queried)
// Assign 'queried' parameter to the group resource directory. // Assign 'queried' parameter to the group resource directory.
// Return true if this directory exists. // Return true if this directory exists.
// Otherwise clears the parameter and returns false.
// //
// Corresponds to foamEtcFile -mode=g // Corresponds to foamEtcFile -mode=g
// Looks for // Looks for
@ -102,6 +123,7 @@ static inline bool groupResourceDir(Foam::fileName& queried)
// Assign 'queried' parameter to the OpenFOAM etc/ resource directory. // Assign 'queried' parameter to the OpenFOAM etc/ resource directory.
// Return true if it exists. // Return true if it exists.
// Otherwise clears the parameter and returns false.
// //
// Corresponds to foamEtcFile -mode=o // Corresponds to foamEtcFile -mode=o
// Looks for // Looks for
@ -122,6 +144,7 @@ static inline bool projectResourceDir(Foam::fileName& queried)
Foam::fileNameList searchEtc Foam::fileNameList searchEtc
( (
const Foam::fileName& name, const Foam::fileName& name,
unsigned short location,
const bool findFirst, const bool findFirst,
bool (*accept)(const Foam::fileName&) bool (*accept)(const Foam::fileName&)
) )
@ -131,13 +154,23 @@ Foam::fileNameList searchEtc
const Foam::fileName version(std::to_string(Foam::foamVersion::api)); const Foam::fileName version(std::to_string(Foam::foamVersion::api));
Foam::fileNameList list; Foam::fileNameList list;
Foam::fileName dir, candidate; 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 // User resource directories
if (userResourceDir(dir)) if ((location & 0700) && userResourceDir(queried))
{ {
candidate = dir/version/name; candidate = queried/version/name;
if (accept(candidate)) if (accept(candidate))
{ {
list.append(std::move(candidate)); list.append(std::move(candidate));
@ -147,7 +180,7 @@ Foam::fileNameList searchEtc
} }
} }
candidate = dir/name; candidate = queried/name;
if (accept(candidate)) if (accept(candidate))
{ {
list.append(std::move(candidate)); list.append(std::move(candidate));
@ -159,9 +192,9 @@ Foam::fileNameList searchEtc
} }
// Group (site) resource directories // Group (site) resource directories
if (groupResourceDir(dir)) if ((location & 0070) && groupResourceDir(queried))
{ {
candidate = dir/version/name; candidate = queried/version/name;
if (accept(candidate)) if (accept(candidate))
{ {
list.append(std::move(candidate)); list.append(std::move(candidate));
@ -171,7 +204,7 @@ Foam::fileNameList searchEtc
} }
} }
candidate = dir/name; candidate = queried/name;
if (accept(candidate)) if (accept(candidate))
{ {
list.append(std::move(candidate)); list.append(std::move(candidate));
@ -183,9 +216,9 @@ Foam::fileNameList searchEtc
} }
// Other (project) resource directory // Other (project) resource directory
if (projectResourceDir(dir)) if ((location & 0007) && projectResourceDir(queried))
{ {
candidate = dir/name; candidate = queried/name;
if (accept(candidate)) if (accept(candidate))
{ {
list.append(std::move(candidate)); list.append(std::move(candidate));
@ -207,27 +240,27 @@ Foam::fileNameList Foam::etcDirs(bool test)
const Foam::fileName version(std::to_string(Foam::foamVersion::api)); const Foam::fileName version(std::to_string(Foam::foamVersion::api));
Foam::fileNameList list(5); Foam::fileNameList list(5);
Foam::fileName dir; Foam::fileName queried;
label nDirs = 0; label nDirs = 0;
// User resource directories // User resource directories
if (userResourceDir(dir) || (!test && dir.size())) if (userResourceDir(queried) || (!test && queried.size()))
{ {
list[nDirs++] = dir/version; list[nDirs++] = queried/version;
list[nDirs++] = dir; list[nDirs++] = queried;
} }
// Group (site) resource directories // Group (site) resource directories
if (groupResourceDir(dir) || (!test && dir.size())) if (groupResourceDir(queried) || (!test && queried.size()))
{ {
list[nDirs++] = dir/version; list[nDirs++] = queried/version;
list[nDirs++] = dir; list[nDirs++] = queried;
} }
// Other (project) resource directory // Other (project) resource directory
if (projectResourceDir(dir) || (!test && dir.size())) if (projectResourceDir(queried) || (!test && queried.size()))
{ {
list[nDirs++] = dir; list[nDirs++] = queried;
} }
list.resize(nDirs); list.resize(nDirs);
@ -239,13 +272,15 @@ Foam::fileNameList Foam::etcDirs(bool test)
Foam::fileNameList Foam::findEtcDirs Foam::fileNameList Foam::findEtcDirs
( (
const fileName& name, const fileName& name,
const bool findFirst const bool findFirst,
unsigned short location
) )
{ {
return return
searchEtc searchEtc
( (
name, name,
location,
findFirst, findFirst,
[](const fileName& f){ return Foam::isDir(f); } [](const fileName& f){ return Foam::isDir(f); }
); );
@ -256,7 +291,8 @@ Foam::fileNameList Foam::findEtcFiles
( (
const fileName& name, const fileName& name,
const bool mandatory, const bool mandatory,
const bool findFirst const bool findFirst,
unsigned short location
) )
{ {
fileNameList list; fileNameList list;
@ -267,6 +303,7 @@ Foam::fileNameList Foam::findEtcFiles
list = searchEtc list = searchEtc
( (
name, name,
location,
findFirst, findFirst,
[](const fileName& f){ return Foam::isFile(f); } [](const fileName& f){ return Foam::isFile(f); }
); );
@ -274,11 +311,16 @@ Foam::fileNameList Foam::findEtcFiles
if (mandatory && list.empty()) if (mandatory && list.empty())
{ {
// Abort if file is mandatory but not found // Abort if file is mandatory but not found.
// Use a direct exit, since this could occur before anything is
// setup at all.
std::cerr std::cerr
<< "--> FOAM FATAL ERROR in Foam::findEtcFiles()" << "--> FOAM FATAL ERROR :\n "
" : could not find mandatory file\n '" "Could not find mandatory etc file (mode="
<< name.c_str() << "'\n\n" << std::endl; << locationToString(location) << ")\n '"
<< name.c_str() << "'\n"
<< std::endl;
::exit(1); ::exit(1);
} }
@ -286,16 +328,42 @@ Foam::fileNameList Foam::findEtcFiles
} }
Foam::fileName Foam::findEtcFile(const fileName& name, const bool mandatory) Foam::fileName Foam::findEtcDir
(
const fileName& name,
unsigned short location
)
{ {
fileNameList list(findEtcFiles(name, mandatory, true)); fileNameList list(findEtcDirs(name, true, location));
fileName found;
if (list.size()) if (list.size())
{ {
return list.first(); found = std::move(list.first());
} }
return fileName(); return found;
}
Foam::fileName Foam::findEtcFile
(
const fileName& name,
const bool mandatory,
unsigned short location
)
{
fileNameList list(findEtcFiles(name, mandatory, true, location));
fileName found;
if (list.size())
{
found = std::move(list.first());
}
return found;
} }

View File

@ -60,25 +60,38 @@ fileNameList etcDirs(bool test=true);
fileNameList findEtcDirs fileNameList findEtcDirs
( (
const fileName& name, //!< The directory to search for const fileName& name, //!< The directory to search for
const bool findFirst=false //!< Stop after locating the first directory 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 from user/group/other directories.
// //
// The search hierarchy corresponds to that of the 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.
// -# \b user settings //
// -# \b user settings (\c location=0700)
// - ~/.OpenFOAM/{PROJECT_API} // - ~/.OpenFOAM/{PROJECT_API}
// - ~/.OpenFOAM/ // - ~/.OpenFOAM/
// -# \b group settings // -# \b group settings (\c location=0070)
// - $WM_PROJECT_SITE/{PROJECT_API}/etc/ // - $WM_PROJECT_SITE/{PROJECT_API}/etc/
// - $WM_PROJECT_SITE/etc/ // - $WM_PROJECT_SITE/etc/
// -# \b other (shipped) settings // -# \b other (shipped) settings (\c location=0007)
// - $WM_PROJECT_DIR/etc/ // - $WM_PROJECT_DIR/etc/
// //
// Where {PROJECT_API} is the value of the OPENFOAM define. // Where {PROJECT_API} corresponds to the foamVersion::api value.
// - \b \$WM_PROJECT_SITE : If unset, uses $WM_PROJECT_DIR/site //
// \note When \c \$WM_PROJECT_SITE is unset, uses \c $WM_PROJECT_DIR/site
// //
// \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.
@ -86,7 +99,8 @@ fileNameList findEtcFiles
( (
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
const bool findFirst=false //!< Stop after locating the first directory const bool findFirst=false, //!< Stop after locating the first directory
unsigned short location=0777 //!< User/group/other location
); );
@ -97,7 +111,8 @@ fileNameList 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
); );

View File

@ -37,10 +37,33 @@ License
namespace Foam namespace Foam
{ {
// Return the file location mode (string) as a numerical value.
//
// - u : location mask 0700
// - g : location mask 0070
// - o : location mask 0007
//
static inline unsigned short modeToLocation
(
const std::string& mode,
std::size_t pos = 0
)
{
unsigned short where(0);
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
return where;
}
// Expand a leading <tag>/ // Expand a leading <tag>/
// Convenient for frequently used directories // Convenient for frequently used directories
// //
// <etc>/ => user/group/other OpenFOAM directory // <etc>/ => user/group/other etc - findEtcFile()
// <etc(:[ugo]+)?>/ => user/group/other etc - findEtcFile()
// <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
@ -52,7 +75,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
} }
auto delim = s.find(e); auto delim = s.find(e);
if (delim == std::string::npos) if (std::string::npos == delim)
{ {
return; // Error: no closing delim - ignore expansion return; // Error: no closing delim - ignore expansion
} }
@ -73,6 +96,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
} }
const std::string tag(s, 1, delim-2); const std::string tag(s, 1, delim-2);
const auto tagLen = tag.length();
// Note that file is also allowed to be an empty string. // Note that file is also allowed to be an empty string.
@ -88,6 +112,12 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
{ {
s = fileName(Foam::getEnv("FOAM_CASE"))/tag/file; s = fileName(Foam::getEnv("FOAM_CASE"))/tag/file;
} }
else if (tagLen >= 4 && tag.compare(0, 4, "etc:") == 0)
{
// <etc:ugo> type of tag - convert "ugo" to numeric
s = findEtcFile(file, false, modeToLocation(tag, 4));
}
} }

View File

@ -219,30 +219,45 @@ namespace stringOps
// -# environment variables // -# environment variables
// - "$VAR", "${VAR}" // - "$VAR", "${VAR}"
// -# current directory // -# current directory
// - leading "./" : the current directory // - leading "./"
// : the current directory - Foam::cwd()
// -# leading tag expansion for commonly used directories // -# leading tag expansion for commonly used directories
// - \<etc\>/ : user/group/other OpenFOAM directory // - <b> \<etc\>/ </b>
// - \<case\>/ : FOAM_CASE directory // : user/group/other OpenFOAM etc directory
// - \<constant\>/ : FOAM_CASE/constant directory // - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b>
// - \<system\>/ : FOAM_CASE/system directory // : user/group/other etc with specified location mode
// - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory
// - <b> \<constant\>/ </b>
// : The \c $FOAM_CASE/constant directory
// - <b> \<system\>/ </b>
// : The \c $FOAM_CASE/system directory
// -# tilde expansion // -# tilde expansion
// - leading "~/" : home directory // - leading "~/" : home directory
// - leading "~user" : home directory for specified user // - leading "~user" : home directory for specified user
// //
// Supports default and alternative values as per the POSIX shell. // Supports default and alternative values as per the POSIX shell.
// \code // \code
// a) "${parameter:-defValue}" // 1. "${parameter:-defValue}"
// b) "${parameter:+altValue}" // 2. "${parameter:+altValue}"
// \endcode // \endcode
// a) If parameter is unset or null, the \c defValue is substituted. // -# If parameter is unset or null, the \c defValue is substituted.
// Otherwise, the value of parameter is substituted. // Otherwise, the value of parameter is substituted.
// // -# If parameter is unset or null, nothing is substituted.
// b) If parameter is unset or null, nothing is substituted. // Otherwise the \c altValue is substituted.
// Otherwise the \c altValue is substituted. // .
// //
// General behavior:
// - Any unknown entries are removed silently, if allowEmpty is true. // - Any unknown entries are removed silently, if allowEmpty is true.
// - Malformed entries (eg, brace mismatch, sigil followed by bad chars) // - Malformed entries (eg, brace mismatch, sigil followed by bad chars)
// are left as is. // are left as is.
//
// An example of using the specified location mode
// \code
// fileName controlDict(stringOps::expand("<etc:o>/controlDict"));
// // OR
// fileName controlDict(findEtcFile("controlDict", false, 0007));
// \endcode
// //
// \note Deprecated(2018-11) Use "<etc>" instead of the rarely used // \note Deprecated(2018-11) Use "<etc>" instead of the rarely used
// "~OpenFOAM" expansion // "~OpenFOAM" expansion
@ -263,28 +278,35 @@ namespace stringOps
// -# current directory // -# current directory
// - leading "./" : the current directory // - leading "./" : the current directory
// -# leading tag expansion for commonly used directories // -# leading tag expansion for commonly used directories
// - \<etc\>/ : user/group/other OpenFOAM directory // - <b> \<etc\>/ </b>
// - \<case\>/ : FOAM_CASE directory // : user/group/other OpenFOAM etc directory
// - \<constant\>/ : FOAM_CASE/constant directory // - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b>
// - \<system\>/ : FOAM_CASE/system directory // : user/group/other etc with specified location mode
// - <b> \<case\>/ </b>
// : The \c $FOAM_CASE directory
// - <b> \<constant\>/ </b>
// : The \c $FOAM_CASE/constant directory
// - <b> \<system\>/ </b>
// : The \c $FOAM_CASE/system directory
// -# tilde expansion // -# tilde expansion
// - leading "~/" : home directory // - leading "~/" : home directory
// - leading "~user" : home directory for specified user // - leading "~user" : home directory for specified user
// //
// Supports default and alternative values as per the POSIX shell. // Supports default and alternative values as per the POSIX shell.
// \code // \code
// a) "${parameter:-defValue}" // 1. "${parameter:-defValue}"
// b) "${parameter:+altValue}" // 2. "${parameter:+altValue}"
// \endcode // \endcode
// a) If parameter is unset or null, the \c defValue is substituted. // -# If parameter is unset or null, the \c defValue is substituted.
// Otherwise, the value of parameter is substituted. // Otherwise, the value of parameter is substituted.
// // -# If parameter is unset or null, nothing is substituted.
// b) If parameter is unset or null, nothing is substituted. // Otherwise the \c altValue is substituted.
// Otherwise the \c altValue is substituted. // .
// //
// General behavior:
// - Any unknown entries are removed silently if allowEmpty is true. // - Any unknown entries are removed silently if allowEmpty is true.
// - Malformed entries (eg, brace mismatch, sigil followed by bad chars) // - Malformed entries (eg, brace mismatch, sigil followed by bad chars)
// are left as is. // are left as is.
// //
// \note Deprecated(2018-11) Use "<etc>" instead of the rarely used // \note Deprecated(2018-11) Use "<etc>" instead of the rarely used
// "~OpenFOAM" expansion // "~OpenFOAM" expansion