Generalization of temporary file and directory creation

This commit is contained in:
Matthias Koefferlein 2023-11-01 18:18:26 +01:00
parent 880c8fbb05
commit b78f01387f
6 changed files with 248 additions and 9 deletions

View File

@ -305,7 +305,6 @@ SaltGrainDetailsTextWidget::details_text ()
if (! d->url.empty ()) {
stream << " - ";
stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]<br/>";
// @@@ TODO: protocol and branch
}
}
stream << "</p>";

View File

@ -187,7 +187,6 @@ SaltGrainPropertiesDialog::update_controls ()
dependency_changed (item, 0);
item->setData (1, Qt::UserRole, tl::to_qstring (d->version));
dependency_changed (item, 1);
// @@@ TODO: protocol and branch?
item->setData (2, Qt::UserRole, tl::to_qstring (d->url));
dependency_changed (item, 2);
@ -254,7 +253,6 @@ SaltGrainPropertiesDialog::update_data ()
dep.name = tl::to_string (name);
dep.version = tl::to_string (version);
dep.url = tl::to_string (url);
// @@@ TODO: set protocol and branch
m_grain.dependencies ().push_back (dep);
}

View File

@ -27,6 +27,7 @@
#include "tlEnv.h"
#include <cctype>
#include <fstream>
// Use this define to print debug output
// #define FILE_UTILS_VERBOSE
@ -1018,4 +1019,108 @@ get_module_path (void *addr)
#endif
}
std::string
tmpfile (const std::string &domain)
{
std::string tmp = tl::get_env ("TMPDIR");
if (tmp.empty ()) {
tmp = tl::get_env ("TMP");
}
if (tmp.empty ()) {
#if defined(_WIN32)
throw tl::Exception (tl::to_string (tr ("TMP and TMPDIR not set - cannot create temporary file")));
#else
tmp = "/tmp";
#endif
}
std::string templ = tl::combine_path (tmp, domain + "XXXXXX");
char *tmpstr = strdup (templ.c_str ());
#if defined(_WIN32)
if (_mktemp_s (tmpstr, templ) != 0) {
free (tmpstr);
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder name in %s")), tmp);
}
// for compatibility with Linux, create the file as an empty one
std::ofstream os (tmpstr);
if (os.bad ()) {
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder in %s")), tmp);
}
os.close ();
#else
int fd = mkstemp (tmpstr);
if (fd < 0) {
free (tmpstr);
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder in %s")), tmp);
}
close (fd);
#endif
std::string res = tmpstr;
free (tmpstr);
return res;
}
TemporaryFile::TemporaryFile (const std::string &domain)
{
m_path = tmpfile (domain);
}
TemporaryFile::~TemporaryFile ()
{
tl::rm_file (m_path);
}
std::string
tmpdir (const std::string &domain)
{
std::string tmp = tl::get_env ("TMPDIR");
if (tmp.empty ()) {
tmp = tl::get_env ("TMP");
}
if (tmp.empty ()) {
#if defined(_WIN32)
throw tl::Exception (tl::to_string (tr ("TMP and TMPDIR not set - cannot create temporary file")));
#else
tmp = "/tmp";
#endif
}
std::string templ = tl::combine_path (tmp, domain + "XXXXXX");
char *tmpstr = strdup (templ.c_str ());
#if defined(_WIN32)
if (_mktemp_s (tmpstr, templ) != 0) {
free (tmpstr);
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder name in %s")), tmp);
}
if (! tl::mkdir (tmpstr)) {
free (tmpstr);
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder in %s")), tmp);
}
#else
if (mkdtemp (tmpstr) == NULL) {
free (tmpstr);
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder in %s")), tmp);
}
#endif
std::string res = tmpstr;
free (tmpstr);
return res;
}
TemporaryDirectory::TemporaryDirectory (const std::string &domain)
{
m_path = tmpdir (domain);
}
TemporaryDirectory::~TemporaryDirectory ()
{
tl::rm_dir_recursive (m_path);
}
}

View File

@ -188,6 +188,68 @@ std::string TL_PUBLIC current_dir ();
*/
bool TL_PUBLIC chdir (const std::string &path);
/**
* @brief Gets a temporary file path
*
* This function will make a temporary file with a unique name.
* The "domain" string is used as part of the file name as an disambiguator.
*
* The function reads $TMPDIR or $TMP to define the location of the temporary
* directory. On Linux, the default is /tmp.
*
* The file is created and it is the responsibility of the caller to remove
* the file.
*/
std::string TL_PUBLIC tmpfile (const std::string &domain = std::string ());
/**
* @brief A class wrapping a temporary file
*
* In the destructor of this class, the temporary file will be deleted again.
*/
class TL_PUBLIC TemporaryFile
{
public:
TemporaryFile (const std::string &domain = std::string ());
~TemporaryFile ();
const std::string &path () const
{
return m_path;
}
private:
std::string m_path;
};
/**
* @brief Gets a temporary folder path
*
* Similar to "tmpfile", but will create a new, empty folder. Again it is the
* reposibility of the caller to clean up.
*/
std::string TL_PUBLIC tmpdir (const std::string &domain = std::string ());
/**
* @brief A class wrapping a temporary directory
*
* In the destructor of this class, the temporary directory will be deleted again.
*/
class TL_PUBLIC TemporaryDirectory
{
public:
TemporaryDirectory (const std::string &domain = std::string ());
~TemporaryDirectory ();
const std::string &path () const
{
return m_path;
}
private:
std::string m_path;
};
/**
* @brief This function splits the path into it's components
* On Windows, the first component may be the drive prefix ("C:") or

View File

@ -78,12 +78,7 @@ GitObject::GitObject (const std::string &local_path)
InitHelper::ensure_initialized ();
if (local_path.empty ()) {
// @@@ generic tempnam on Windows/Posix ...
char tmp[] = "/tmp/git2klayoutXXXXXX";
if (mkdtemp (tmp) == NULL) {
throw tl::Exception (tl::to_string (tr ("Unable to create temporary folder: %s")), (const char *) tmp);
}
m_local_path = tmp;
m_local_path = tl::tmpdir ("git2klayout");
m_is_temp = true;
}

View File

@ -875,3 +875,83 @@ TEST (20)
EXPECT_EQ (tl::absolute_file_path ("~"), tl::get_home_path ());
EXPECT_EQ (tl::absolute_file_path (tl::combine_path ("~", "test")), tl::combine_path (tl::get_home_path (), "test"));
}
// tmpfile
TEST (21)
{
std::string p = tl::tmpfile ("tl_tests");
EXPECT_EQ (tl::file_exists (p), true);
std::ofstream os (p);
os << "A test";
os.close ();
tl::InputStream is (p);
EXPECT_EQ (is.read_all (), "A test");
EXPECT_EQ (tl::rm_file (p), true);
EXPECT_EQ (tl::file_exists (p), false);
}
// TemporaryFile
TEST (22)
{
std::string p;
{
tl::TemporaryFile tf ("tl_tests");
p = tf.path ();
EXPECT_EQ (tl::file_exists (tf.path ()), true);
std::ofstream os (tf.path ());
os << "A test";
os.close ();
tl::InputStream is (tf.path ());
EXPECT_EQ (is.read_all (), "A test");
}
EXPECT_EQ (tl::file_exists (p), false);
}
// tmpdir
TEST (23)
{
std::string p = tl::tmpdir ("tl_tests");
EXPECT_EQ (tl::file_exists (p), true);
EXPECT_EQ (tl::is_dir (p), true);
std::ofstream os (tl::combine_path (p, "test"));
os << "A test";
os.close ();
tl::InputStream is (tl::combine_path (p, "test"));
EXPECT_EQ (is.read_all (), "A test");
EXPECT_EQ (tl::rm_dir_recursive (p), true);
EXPECT_EQ (tl::file_exists (p), false);
}
// TemporaryDirectory object
TEST (24)
{
std::string p;
{
tl::TemporaryDirectory tmpdir ("tl_tests");
p = tmpdir.path ();
EXPECT_EQ (tl::file_exists (p), true);
EXPECT_EQ (tl::is_dir (p), true);
std::ofstream os (tl::combine_path (p, "test"));
os << "A test";
os.close ();
tl::InputStream is (tl::combine_path (p, "test"));
EXPECT_EQ (is.read_all (), "A test");
}
EXPECT_EQ (tl::file_exists (p), false);
}