Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions src/coreComponents/dataRepository/xmlWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "common/format/StringUtilities.hpp"
#include "common/MpiWrapper.hpp"
#include "dataRepository/KeyNames.hpp"
#include "common/Path.hpp"

namespace geos
{
Expand Down Expand Up @@ -268,6 +269,88 @@ string buildMultipleInputXML( string_array const & inputFileList,
return inputFileName;
}

void collectIncluded( string const & filePath,
std::set< string > & collection )
{
xmlDocument doc;
xmlResult result = doc.loadFile( filePath );
GEOS_THROW_IF( !result,
GEOS_FMT( "Could not load XML file '{}': {}", filePath, result.description() ),
InputError );
xmlNode rootNode = doc.getFirstChild();

string const currentDir = splitPath( filePath ).first;

for ( auto & includedNode : rootNode.children( includedListTag ) )
{
for ( auto & fileNode : includedNode.children() )
{
string const fileName = fileNode.attribute( "name" ).value();

GEOS_THROW_IF( fileName.empty(),
GEOS_FMT( "An included file entry in '{}' has an empty or missing 'name' attribute.", filePath ),
InputError );
Comment thread
kdrienCG marked this conversation as resolved.
Outdated

string absolutePath = isAbsolutePath( fileName )
? getAbsolutePath( fileName )
: getAbsolutePath( joinPath( currentDir, fileName ) );
collection.insert( absolutePath );
}
}
}

std::set< string > collectIncluded( string const & filePath )
{
std::set< string > collection;
collectIncluded( filePath, collection );
return collection;
}

void collectIncludedRecursive( string const & filePath,
std::set< string > & collection )
{
// We want absolute paths
string const absFilePath = getAbsolutePath( filePath );

if ( collection.count( absFilePath ) > 0 )
{
return;
}
collection.insert( absFilePath );

xmlDocument doc;
xmlResult result = doc.loadFile( absFilePath );
GEOS_THROW_IF( !result,
GEOS_FMT( "Could not load XML file '{}': {}", filePath, result.description() ),
InputError );
xmlNode rootNode = doc.getFirstChild();

string const currentDir = splitPath( filePath ).first;

for ( auto & includedNode : rootNode.children( includedListTag ) )
{
for ( auto & fileNode : includedNode.children( includedFileTag ) )
{
string const includedFilePath = fileNode.attribute( "name" ).value();

if ( includedFilePath.empty() ) { continue; }

string includedAbsPath = isAbsolutePath( includedFilePath )
? getAbsolutePath( includedFilePath )
: getAbsolutePath( joinPath(currentDir, includedFilePath) );
collectIncludedRecursive( includedAbsPath,
collection );
}
}
}

std::set< string > collectIncludedRecursive( string const & filePath )
{
std::set< string > collection;
collectIncludedRecursive( filePath, collection );
return collection;
}

bool isFileMetadataAttribute( string const & name )
{
static const std::set< string > fileMetadataAttributes {
Expand Down
44 changes: 44 additions & 0 deletions src/coreComponents/dataRepository/xmlWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,50 @@ constexpr char const includedFileTag[] = "File";
string buildMultipleInputXML( string_array const & inputFileList,
string const & outputDir = {} );

/**
* @brief Collect the absolute paths of XML files directly included
* by a given xml file
* @param[in] filePath absolute path of the xml file to inspect
* @param[inout] collection collection to append with absolute file paths
*
* Only one level of inclusion is collected (files included by the included
* files are not added). See collectIncludedRecursive if you want this behavior.
* Duplicate entries are not inserted in @p collection
*/
void collectIncluded( string const & filePath,
std::set< string > & collection );

/**
* @brief Collect the absolute paths of XML files directly included
* by a given xml file
* @param[in] filePath absolute path of the xml file to inspect
* @return a collection of absolute paths
*
* Only one level of inclusion is collected (files included by the included
* files are not added). See collectIncludedRecursive if you want this behavior.
* Duplicate entries are not inserted in @p collection
*/
std::set< string > collectIncluded( string const & filePath );

/**
* @brief Recursively collect the absolute paths of an XML file and all XML
* files it includes
* @param[in] filePath absolute path of the root XML file
* @param[inout] collection collection to append with absolute file paths
* of every visisted file (including @p filePath itself)
Comment thread
kdrienCG marked this conversation as resolved.
Outdated
*/
void collectIncludedRecursive( string const & filePath,
std::set< string > & collection );

/**
* @brief Recursively collect the absolute paths of an XML file and all XML
* files it includes
* @param[in] filePath absolute path of the root XML file
* @return a collection of absolute paths of every visited file (including
* @p filePath itself)
*/
std::set< string > collectIncludedRecursive( string const & filePath );

/**
* @return true if the attribute with the specified name declares metadata relative to the xml
* @param name the name of an attribute
Expand Down
2 changes: 2 additions & 0 deletions src/coreComponents/fileIO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Contains:
#
set( fileIO_headers
LogLevelsInfo.hpp
Outputs/ArchiveInputDeck.hpp
Outputs/BlueprintOutput.hpp
Outputs/MemoryStatsOutput.hpp
Outputs/OutputBase.hpp
Expand All @@ -43,6 +44,7 @@ set( fileIO_headers
# Specify all sources
#
set( fileIO_sources
Outputs/ArchiveInputDeck.cpp
Outputs/BlueprintOutput.cpp
Outputs/MemoryStatsOutput.cpp
Outputs/OutputBase.cpp
Expand Down
122 changes: 122 additions & 0 deletions src/coreComponents/fileIO/Outputs/ArchiveInputDeck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* ------------------------------------------------------------------------------------------------------------
* SPDX-License-Identifier: LGPL-2.1-only
*
* Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
* Copyright (c) 2018-2024 TotalEnergies
* Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2023-2024 Chevron
* Copyright (c) 2019- GEOS/GEOSX Contributors
* All rights reserved
*
* See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
* ------------------------------------------------------------------------------------------------------------
*/

/**
* @file ArchiveInputDeck.cpp
*/

#include "ArchiveInputDeck.hpp"

#include "common/Path.hpp"
#include "dataRepository/xmlWrapper.hpp"

#include <chrono>
#include <filesystem>


namespace geos
{

using namespace dataRepository;

namespace archiveInputDeck
{

namespace
{

string makeTimestamp()
{
auto const now = std::chrono::system_clock::now();
auto const time_t_now = std::chrono::system_clock::to_time_t( now );
std::ostringstream timestampStream;
timestampStream << std::put_time( std::localtime( &time_t_now ), "%Y%m%d_%H%M%S" );
return timestampStream.str();
Comment thread
kdrienCG marked this conversation as resolved.
}

std::set< string > collectAbsFilePaths( string_array const & fileNames )
{
std::set< string > collection;
for ( string const & fileName : fileNames )
{
xmlWrapper::collectIncludedRecursive( fileName, collection );
}
return collection;
}

/// @brief Prefixes a file path string if it is located "behind" the
/// specified directory
/// @param absFilePath The absolute path to the file
/// @param absDirPath The absolute path to the directory
/// @return A relative path of the file prefixed with "__" for every "../"
/// from the directory location
///
/// Example:
/// @code
/// std::string foo = prefixBackwardPath( "/usr/foo/file.txt", "/usr/bar/buzz" )
/// assert( foo == "____foo/file.txt" )
/// @endcode
string prefixBackwardPath( string const & absFilePath, string const & absDirPath )
{
string relPath = std::filesystem::relative( std::filesystem::path( absFilePath ),
std::filesystem::path( absDirPath ) );

string prefix;
while( relPath.size() >= 3 && relPath.substr( 0, 3 ) == "../" )
{
prefix += "__";
relPath = relPath.substr( 3 );
}

return prefix + relPath;
}

}

void archiveInputDeck( string_array const & inputFileNames,
string const & outputDirectory )
{
if ( inputFileNames.empty() )
{
return;
}

string const timestamp = makeTimestamp();
string const archiveDir = joinPath( outputDirectory, "archive_inputFiles", timestamp );
makeDirsForPath( archiveDir + "/" );
Comment thread
kdrienCG marked this conversation as resolved.

Comment thread
kdrienCG marked this conversation as resolved.
Outdated
string const baseDir = splitPath( getAbsolutePath(inputFileNames[0]) ).first;
std::set< string > absFilePaths = collectAbsFilePaths( inputFileNames );

for ( string const & absFilePath : absFilePaths )
{
string const destPath = joinPath( archiveDir, prefixBackwardPath( absFilePath, baseDir ) );
makeDirsForPath( splitPath( destPath ).first + "/" );

std::error_code ec;
bool copied = std::filesystem::copy_file( absFilePath,
destPath,
std::filesystem::copy_options::overwrite_existing,
ec );
GEOS_LOG_IF( !copied,
GEOS_FMT( "Failed to copy archive file '{}' into '{}': {}",
absFilePath, destPath, ec.message() ) );
Comment thread
kdrienCG marked this conversation as resolved.
Outdated
}

}

} /* namespace archiveInputDeck */

} /* namespace geos */
53 changes: 53 additions & 0 deletions src/coreComponents/fileIO/Outputs/ArchiveInputDeck.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* ------------------------------------------------------------------------------------------------------------
* SPDX-License-Identifier: LGPL-2.1-only
*
* Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
* Copyright (c) 2018-2024 TotalEnergies
* Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2023-2024 Chevron
* Copyright (c) 2019- GEOS/GEOSX Contributors
* All rights reserved
*
* See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
* ------------------------------------------------------------------------------------------------------------
*/

/**
* @file ArchiveInputDeck.hpp
*/

#ifndef GEOS_FILEIO_OUTPUTS_ARCHIVEINPUTDECK_HPP_
#define GEOS_FILEIO_OUTPUTS_ARCHIVEINPUTDECK_HPP_

#include "common/DataTypes.hpp"

namespace geos
{

namespace archiveInputDeck
{

/**
* @brief Copy XML input files into the output directory, preserving the
* folder structure
* @param inputFileNames Container of XML file names to start the copy from
* @param outputDirectory The output directory to copy files into
*
* Copy XML input files and every included files they contain (specified in
* the <Included> tag. This function creates a somewhat similar folder
* structure to the actual structure in the disk.
*
* Note: XML files that are located "behind" the callpoint (the path to
* the first input file given as the -i paramater) will be prefixed
Comment thread
kdrienCG marked this conversation as resolved.
Outdated
* with "__" for every "../" in the relative path from the callpoint.
*/
void archiveInputDeck( string_array const & inputFileNames,
string const & outputDirectory );

} /* namespace archiveInputDeck */

} /* namespace geos */


#endif // GEOS_FILEIO_OUTPUTS_ARCHIVEINPUTDECK_HPP_
3 changes: 3 additions & 0 deletions src/coreComponents/mainInterface/ProblemManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "finiteVolume/FluxApproximationBase.hpp"
#include "finiteVolume/HybridMimeticDiscretization.hpp"
#include "fieldSpecification/FieldSpecificationManager.hpp"
#include "fileIO/Outputs/ArchiveInputDeck.hpp"
#include "fileIO/Outputs/OutputBase.hpp"
#include "fileIO/Outputs/OutputManager.hpp"
#include "functions/FunctionManager.hpp"
Expand Down Expand Up @@ -221,6 +222,8 @@ void ProblemManager::parseCommandLineInput()
GEOS_LOG_RANK_0( "Opened XML file: " << absPath );
}

archiveInputDeck::archiveInputDeck( opts.inputFileNames, outputDirectory );
Comment thread
kdrienCG marked this conversation as resolved.
Outdated

inputFileName = xmlWrapper::buildMultipleInputXML( opts.inputFileNames, outputDirectory );

string & schemaName = commandLine.getReference< string >( viewKeys.schemaFileName );
Expand Down
Loading