diff --git a/src/lay/lay/laySaltGrainDetailsTextWidget.cc b/src/lay/lay/laySaltGrainDetailsTextWidget.cc index 1992b20c9e..28eb81c6a9 100644 --- a/src/lay/lay/laySaltGrainDetailsTextWidget.cc +++ b/src/lay/lay/laySaltGrainDetailsTextWidget.cc @@ -305,7 +305,6 @@ SaltGrainDetailsTextWidget::details_text () if (! d->url.empty ()) { stream << " - "; stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
"; - // @@@ TODO: protocol and branch } } stream << "

"; diff --git a/src/lay/lay/laySaltGrainPropertiesDialog.cc b/src/lay/lay/laySaltGrainPropertiesDialog.cc index 22ad35005a..061eee1ca2 100644 --- a/src/lay/lay/laySaltGrainPropertiesDialog.cc +++ b/src/lay/lay/laySaltGrainPropertiesDialog.cc @@ -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); } diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index 747d21c6fe..752c4085ce 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -27,6 +27,7 @@ #include "tlEnv.h" #include +#include // 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); +} + + } diff --git a/src/tl/tl/tlFileUtils.h b/src/tl/tl/tlFileUtils.h index 0649b4078c..474ec7e29d 100644 --- a/src/tl/tl/tlFileUtils.h +++ b/src/tl/tl/tlFileUtils.h @@ -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 diff --git a/src/tl/tl/tlGit.cc b/src/tl/tl/tlGit.cc index 95470580f3..12298d93fc 100644 --- a/src/tl/tl/tlGit.cc +++ b/src/tl/tl/tlGit.cc @@ -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; } diff --git a/src/tl/unit_tests/tlFileUtilsTests.cc b/src/tl/unit_tests/tlFileUtilsTests.cc index 4814901c2e..768b0943a5 100644 --- a/src/tl/unit_tests/tlFileUtilsTests.cc +++ b/src/tl/unit_tests/tlFileUtilsTests.cc @@ -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); +} +