28#include <wx/filename.h>
29#include <wx/tokenzr.h>
48void reportTempDir(
const wxString& aMessage )
50 fprintf( stderr,
"%s\n", aMessage.utf8_string().c_str() );
58void safeRemoveTempDir(
const std::filesystem::path& aPath )
noexcept
61 std::filesystem::remove_all( aPath, ec );
68 reportTempDir( wxString::Format( wxT(
"Cannot remove temporary directory '%s': %s" ),
69 wxString::FromUTF8( aPath.string() ), wxString::FromUTF8( ec.message() ) ) );
88 explicit TEMP_DIR_REMOVER( std::filesystem::path aPath ) noexcept :
89 m_path( std::move( aPath ) )
98 safeRemoveTempDir( m_path );
102 TEMP_DIR_REMOVER(
const TEMP_DIR_REMOVER& ) =
delete;
103 TEMP_DIR_REMOVER& operator=(
const TEMP_DIR_REMOVER& ) =
delete;
105 const std::filesystem::path& Path() const noexcept {
return m_path; }
107 void Release() noexcept { m_released =
true; }
110 std::filesystem::path m_path;
111 bool m_released =
false;
115bool shouldKeepTemp(
const std::filesystem::path& aPath,
const wxString& aKeepEnvValue )
117 const wxString envVar = wxT(
"KICAD_QA_KEEP_TEMP" );
120 if( !wxGetEnv( envVar, &keepEnv ) || keepEnv.IsEmpty() )
124 wxStringTokenizer tokenizer( keepEnv, wxT(
"," ) );
126 while( tokenizer.HasMoreTokens() )
128 wxString token = tokenizer.GetNextToken();
130 if( token == aKeepEnvValue || token == wxT(
"ALL" ) )
134 reportTempDir( wxString::Format( wxT(
"Keeping temporary directory '%s' because %s is set to '%s'" ),
135 wxString::FromUTF8( aPath.string() ), envVar, keepEnv ) );
144std::filesystem::path createTempDir(
const wxString& aPrefix,
const wxString& aSuffix )
147 const std::filesystem::path tempRoot = std::filesystem::temp_directory_path( ec );
150 throw std::runtime_error(
"Cannot determine the temporary directory: " + ec.message() );
154 constexpr size_t k_maxAttempts = 1000;
155 for(
size_t i = 0; i < k_maxAttempts; ++i )
157 const std::filesystem::path candidate =
158 tempRoot / ( aPrefix.utf8_string() +
"_" + std::to_string( i ) + aSuffix.utf8_string() );
160 if( std::filesystem::create_directory( candidate, ec ) )
165 if( ec && ec != std::errc::file_exists )
166 throw std::runtime_error(
"Cannot create temporary directory '" + candidate.string()
167 +
"': " + ec.message() );
171 throw std::runtime_error(
"Cannot find a free temporary directory name with prefix/suffix '"
172 + std::string( aPrefix.utf8_str() ) +
"/" + std::string( aSuffix.utf8_str() ) +
"'" );
185 TEMP_DIR_REMOVER remover( createTempDir( aPrefix, aSuffix ) );
187 m_keep = shouldKeepTemp( remover.Path(), aPrefix );
203 safeRemoveTempDir(
m_path );
214 wxString::Format( wxT(
"Keeping temporary directory '%s'" ), wxString::FromUTF8(
m_path.string() ) ) );
221 throw std::runtime_error(
"Unsafe child path '" + std::string( aChild.utf8_str() ) +
"'" );
229 return wxString::FromUTF8( (
m_path / aName.utf8_string() ).string() );
237 std::filesystem::path childPath =
m_path / aName.utf8_string();
239 if( !std::filesystem::create_directory( childPath ) )
240 throw std::runtime_error(
"Cannot create temporary child directory '" + childPath.string() +
"'" );
256 std::filesystem::path childPath =
m_path / aName.utf8_string();
257 wxFFile file( wxString::FromUTF8( childPath.string() ), wxT(
"w" ) );
259 if( !file.IsOpened() )
260 throw std::runtime_error(
"Cannot create temporary child file '" + childPath.string() +
"'" );
273 const wxString& aName ) :
280 m_manager.LoadProject( projectFile.GetFullPath() );
285 throw std::runtime_error(
"Cannot load temporary project '"
286 + std::string( projectFile.GetFullPath().utf8_str() ) +
"'" );
300 const wxString envValue =
m_dir.PathStr();
302 wxSetEnv( wxT(
"TMPDIR" ), envValue );
303 wxSetEnv( wxT(
"TEMP" ), envValue );
304 wxSetEnv( wxT(
"TMP" ), envValue );
SCOPED_PROCESS_TEMP_DIR(const wxString &aPrefix)
~SCOPED_PROCESS_TEMP_DIR()
std::filesystem::path m_path
static bool s_anyTempDirRetained
wxString CreateChildFileStr(const wxString &aName) const
Create and return the path to a direct child file as a wxString.
void Retain()
Keep this directory after all.
static bool AnyTempDirRetained()
wxString ChildPathStr(const wxString &aName) const
Get the path to a direct child of the temporary directory as a wxString, without creating the child.
wxString CreateChildDirStr(const wxString &aName) const
Create and return the path to a direct child directory as a wxString.
std::filesystem::path CreateChildFile(const wxString &aName) const
Create and return the path to a direct child file.
SCOPED_TEMP_DIR(const wxString &aPrefix, const wxString &aSuffix=wxEmptyString)
Create a temporary directory with a unique name based on the given prefix and optional suffix.
std::filesystem::path CreateChildDir(const wxString &aName) const
Create and return the path to a direct child directory.
SETTINGS_MANAGER & m_manager
SCOPED_TEMP_PROJECT(SETTINGS_MANAGER &aManager, const wxString &aPrefix, const wxString &aName)
static bool IsSafeChildPath(const wxString &aChild)
Check that a child path is safe to append to a parent directory.
void expectSafeChildPath(const wxString &aChild)
static const std::string ProjectFileExtension
Test utilities for timestamps.
Definition of file extensions used in Kicad.