Skip to content

Commit

Permalink
Generalization of temporary file and directory creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Koefferlein committed Nov 1, 2023
1 parent 880c8fb commit b78f013
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 9 deletions.
1 change: 0 additions & 1 deletion src/lay/lay/laySaltGrainDetailsTextWidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>";
Expand Down
2 changes: 0 additions & 2 deletions src/lay/lay/laySaltGrainPropertiesDialog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}

Expand Down
105 changes: 105 additions & 0 deletions src/tl/tl/tlFileUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "tlEnv.h"

#include <cctype>
#include <fstream>

// Use this define to print debug output
// #define FILE_UTILS_VERBOSE
Expand Down Expand Up @@ -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);
}


}
62 changes: 62 additions & 0 deletions src/tl/tl/tlFileUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 1 addition & 6 deletions src/tl/tl/tlGit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
80 changes: 80 additions & 0 deletions src/tl/unit_tests/tlFileUtilsTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit b78f013

Please sign in to comment.