WIP: salt package manager: features for installer

First steps towards installer support. Specifically:
- basic installation methods, basic framework
- file utilities for directory copy

Side effect: temp directories of unit tests are
now cleared prior to test run.
This commit is contained in:
Matthias Koefferlein 2017-03-21 22:20:24 +01:00
parent 10345eea73
commit 820c291623
13 changed files with 623 additions and 31 deletions

View File

@ -51,7 +51,8 @@ HEADERS = \
laySaltGrains.h \
laySaltManagerDialog.h \
laySaltGrainDetailsTextWidget.h \
laySaltGrainPropertiesDialog.h
laySaltGrainPropertiesDialog.h \
laySaltDownloadManager.h
FORMS = \
ClipDialog.ui \
@ -147,7 +148,8 @@ SOURCES = \
laySaltGrains.cc \
laySaltManagerDialog.cc \
laySaltGrainDetailsTextWidget.cc \
laySaltGrainPropertiesDialog.cc
laySaltGrainPropertiesDialog.cc \
laySaltDownloadManager.cc
RESOURCES = layBuildInMacros.qrc \
layHelpResources.qrc \

View File

@ -21,9 +21,14 @@
*/
#include "laySalt.h"
#include "laySaltDownloadManager.h"
#include "tlString.h"
#include "tlFileUtils.h"
#include "tlLog.h"
#include "tlInternational.h"
#include <QFileInfo>
#include <QDir>
namespace lay
{
@ -47,6 +52,32 @@ Salt &Salt::operator= (const Salt &other)
return *this;
}
Salt::flat_iterator
Salt::begin_flat ()
{
validate ();
return mp_flat_grains.begin ();
}
Salt::flat_iterator
Salt::end_flat ()
{
validate ();
return mp_flat_grains.end ();
}
SaltGrain *
Salt::grain_by_name (const std::string &name)
{
validate ();
std::map<std::string, SaltGrain *>::const_iterator g = m_grains_by_name.find (name);
if (g != m_grains_by_name.end ()) {
return g->second;
} else {
return 0;
}
}
void
Salt::add_location (const std::string &path)
{
@ -60,8 +91,7 @@ Salt::add_location (const std::string &path)
lay::SaltGrains gg = lay::SaltGrains::from_path (path);
m_root.add_collection (gg);
mp_flat_grains.clear ();
emit collections_changed ();
invalidate ();
}
void
@ -71,8 +101,7 @@ Salt::remove_location (const std::string &path)
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
m_root.remove_collection (g, false);
mp_flat_grains.clear ();
emit collections_changed ();
invalidate ();
return;
}
}
@ -87,8 +116,7 @@ Salt::refresh ()
}
if (new_root != m_root) {
m_root = new_root;
mp_flat_grains.clear ();
emit collections_changed ();
invalidate ();
}
}
@ -119,12 +147,150 @@ struct NameCompare
}
void
Salt::ensure_flat_present ()
Salt::validate ()
{
if (mp_flat_grains.empty ()) {
add_collection_to_flat (m_root);
m_grains_by_name.clear ();
for (std::vector<SaltGrain *>::const_iterator i = mp_flat_grains.begin (); i != mp_flat_grains.end (); ++i) {
m_grains_by_name.insert (std::make_pair ((*i)->name (), *i));
}
// NOTE: we intentionally sort after the name list has been built - this way
// the first entry will win in the name to grain map.
std::sort (mp_flat_grains.begin (), mp_flat_grains.end (), NameCompare ());
}
}
void
Salt::invalidate ()
{
mp_flat_grains.clear ();
emit collections_changed ();
}
static
bool remove_from_collection (SaltGrains &collection, const std::string &name)
{
bool res = false;
for (SaltGrains::grain_iterator g = collection.begin_grains (); g != collection.end_grains (); ++g) {
if (g->name () == name) {
SaltGrains::grain_iterator gnext = g;
++gnext;
collection.remove_grain (g, true);
res = true;
}
}
for (SaltGrains::collection_iterator gg = collection.begin_collections (); gg != collection.end_collections (); ++gg) {
// TODO: remove this const_cast
if (remove_from_collection (const_cast <SaltGrains &> (*gg), name)) {
res = true;
}
}
return res;
}
bool
Salt::remove_grain (const SaltGrain &grain)
{
tl::info << QObject::tr ("Removing package '%1' ..").arg (tl::to_qstring (grain.name ()));
if (remove_from_collection (m_root, grain.name ())) {
tl::info << QObject::tr ("Package '%1' removed.").arg (tl::to_qstring (grain.name ()));
invalidate ();
return true;
} else {
tl::warn << QObject::tr ("Failed to remove package '%1'.").arg (tl::to_qstring (grain.name ()));
return false;
}
}
bool
Salt::create_grain (const SaltGrain &templ, SaltGrain &target, SaltDownloadManager &download_manager)
{
tl_assert (!m_root.is_empty ());
const SaltGrains *coll = m_root.begin_collections ().operator-> ();
std::string path = target.path ();
if (! path.empty ()) {
coll = 0;
for (SaltGrains::collection_iterator gg = m_root.begin_collections (); gg != m_root.end_collections (); ++gg) {
if (tl::is_parent_path (tl::to_qstring (gg->path ()), tl::to_qstring (path))) {
coll = gg.operator-> ();
break;
}
}
tl_assert (coll != 0);
}
tl::info << QObject::tr ("Installing package '%1' ..").arg (tl::to_qstring (target.name ()));
QDir target_dir (tl::to_qstring (coll->path ()));
try {
// change down to the desired target location and create the directory structure while doing so
std::vector<std::string> name_parts = tl::split (target.name (), "/");
for (std::vector<std::string>::const_iterator n = name_parts.begin (); n != name_parts.end (); ++n) {
QDir subdir (target_dir.filePath (tl::to_qstring (*n)));
if (! subdir.exists ()) {
if (! target_dir.mkdir (tl::to_qstring (*n))) {
throw tl::Exception (tl::to_string (tr ("Unable to create target directory '%1' for installing package").arg (subdir.path ())));
}
if (! target_dir.cd (tl::to_qstring (*n))) {
throw tl::Exception (tl::to_string (tr ("Unable to change to target directory '%1' for installing package").arg (subdir.path ())));
}
}
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
return false;
}
bool res = true;
target = templ;
target.set_path (tl::to_string (target_dir.absolutePath ()));
if (! templ.path ().empty ()) {
// if the template represents an actual folder, use the files from there
tl::info << QObject::tr ("Copying package from '%1' to '%2' ..").arg (tl::to_qstring (templ.path ())).arg (tl::to_qstring (target.path ()));
res = tl::cp_dir_recursive (templ.path (), target.path ());
} else if (! templ.url ().empty ()) {
// otherwise download from the URL
tl::info << QObject::tr ("Downloading package from '%1' to '%2' ..").arg (tl::to_qstring (templ.url ())).arg (tl::to_qstring (target.path ()));
res = download_manager.download (templ.url (), target.path ());
}
if (res) {
tl::info << QObject::tr ("Package '%1' installed").arg (tl::to_qstring (target.name ()));
target.set_installed_time (QDateTime::currentDateTime ());
target.save ();
} else {
tl::warn << QObject::tr ("Failed to install package '%1' - removing files ..").arg (tl::to_qstring (target.name ()));
if (! tl::rm_dir_recursive (target.path ())) {
tl::warn << QObject::tr ("Failed to remove files").arg (tl::to_qstring (target.name ()));
}
}
return res;
}
}

View File

@ -29,9 +29,13 @@
#include <QObject>
#include <map>
namespace lay
{
class SaltDownloadManager;
/**
* @brief The global salt (package manager) object
* This object can be configured to represent a couple of locations.
@ -107,20 +111,48 @@ public:
/**
* @brief A flat iterator of (sorted) grains (begin)
*/
flat_iterator begin_flat ()
{
ensure_flat_present ();
return mp_flat_grains.begin ();
}
flat_iterator begin_flat ();
/**
* @brief A flat iterator of (sorted) grains (end)
*/
flat_iterator end_flat ()
{
ensure_flat_present ();
return mp_flat_grains.end ();
}
flat_iterator end_flat ();
/**
* @brief Gets the grain with the given name
*/
SaltGrain *grain_by_name (const std::string &name);
/**
* @brief Removes a grain from the salt
*
* This operation will remove the grain with the given name from the salt and delete all files and directories related to it.
* If multiple grains with the same name exist, they will all be removed.
*
* Returns true, if the package could be removed successfully.
*/
bool remove_grain (const SaltGrain &grain);
/**
* @brief Creates a new grain from a template
*
* This method will create a folder for a grain with the given path and download or copy
* all files related to this grain. It will copy the download URL from the template into the
* new grain, so updates will come from the original location.
*
* The target's name must be set. If a specific target location is desired, the target's
* path must be set too.
*
* This method refuses to overwrite existing grains, so an update needs to be performed by first
* deleting the grain and then re-installing it.
*
* The target grain will be updated with the installation information. If the target grain
* contains an installation path prior to the installation, this path will be used for the
* installation of the grain files.
*
* Returns true, if the package could be created successfully.
*/
bool create_grain (const SaltGrain &templ, SaltGrain &target, SaltDownloadManager &download_manager);
signals:
/**
@ -131,8 +163,10 @@ signals:
private:
SaltGrains m_root;
std::vector<SaltGrain *> mp_flat_grains;
std::map<std::string, SaltGrain *> m_grains_by_name;
void ensure_flat_present ();
void validate ();
void invalidate ();
void add_collection_to_flat (lay::SaltGrains &gg);
};

View File

@ -0,0 +1,40 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "laySaltDownloadManager.h"
namespace lay
{
SaltDownloadManager::SaltDownloadManager ()
{
// .. nothing yet ..
}
bool
SaltDownloadManager::download (const std::string &url, const std::string &target_dir)
{
// @@@
return false;
}
}

View File

@ -0,0 +1,60 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_laySaltDownloadManager
#define HDR_laySaltDownloadManager
#include "layCommon.h"
#include <QObject>
#include <string>
namespace lay
{
/**
* @brief The download manager
* This class is responsible for handling the downloads for
* grains.
*/
class LAY_PUBLIC SaltDownloadManager
: public QObject
{
Q_OBJECT
public:
/**
* @brief Default constructor
*/
SaltDownloadManager ();
/**
* @brief Downloads the files from the given URL to the given target location
* The target directory needs to exist.
* Returns true, if the download was successful, false otherwise.
*/
bool download (const std::string &url, const std::string &target_dir);
};
}
#endif

View File

@ -593,8 +593,10 @@ SaltGrainPropertiesDialog::exec_dialog (lay::SaltGrain *grain, lay::Salt *salt)
update_controls ();
bool res = exec ();
if (res) {
if (res && *grain != m_grain) {
*grain = m_grain;
// save modified grain
grain->save ();
}
delete dependencies->itemDelegateForColumn (0);

View File

@ -313,6 +313,7 @@ SaltManagerDialog::current_changed ()
} else {
details_frame->setEnabled (true);
delete_button->setEnabled (true);
edit_button->setEnabled (! g->is_readonly ());
}
}

View File

@ -21,6 +21,8 @@
*/
#include "tlFileUtils.h"
#include "tlLog.h"
#include "tlInternational.h"
#include <QDir>
#include <QFileInfo>
@ -28,10 +30,27 @@
namespace tl
{
bool
is_parent_path (const QString &parent, const QString &path)
{
QFileInfo parent_info (parent);
QFileInfo path_info (path);
while (parent_info != path_info) {
path_info = path_info.path ();
if (path_info.isRoot ()) {
return false;
}
}
return true;
}
bool
rm_dir_recursive (const QString &path)
{
QDir dir (path);
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
QFileInfo fi (dir.absoluteFilePath (*e));
@ -39,15 +58,82 @@ rm_dir_recursive (const QString &path)
if (! rm_dir_recursive (fi.filePath ())) {
return false;
}
if (! dir.rmdir (*e)) {
return false;
}
} else if (fi.isFile ()) {
if (! dir.remove (*e)) {
tl::error << QObject::tr ("Unable to remove file: %1").arg (dir.absoluteFilePath (*e));
return false;
}
}
}
QString name = dir.dirName ();
if (dir.cdUp ()) {
if (! dir.rmdir (name)) {
tl::error << QObject::tr ("Unable to remove directory: %1").arg (dir.absoluteFilePath (name));
return false;
}
}
return true;
}
bool
cp_dir_recursive (const QString &source, const QString &target)
{
QDir dir (source);
QDir dir_target (target);
QStringList entries = dir.entryList (QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
QFileInfo fi (dir.absoluteFilePath (*e));
QFileInfo fi_target (dir_target.absoluteFilePath (*e));
if (fi.isDir ()) {
// Copy subdirectory
if (! fi_target.exists ()) {
if (! dir_target.mkdir (*e)) {
tl::error << QObject::tr ("Unable to create target directory: %1").arg (dir_target.absoluteFilePath (*e));
return false;
}
} else if (! fi_target.isDir ()) {
tl::error << QObject::tr ("Unable to create target directory (is a file already): %1").arg (dir_target.absoluteFilePath (*e));
return false;
}
if (! cp_dir_recursive (fi.filePath (), fi_target.filePath ())) {
return false;
}
// TODO: leave symlinks symlinks? How to copy symlinks with Qt?
} else if (fi.isFile ()) {
QFile file (fi.filePath ());
QFile file_target (fi_target.filePath ());
if (! file.open (QIODevice::ReadOnly)) {
tl::error << QObject::tr ("Unable to open source file for reading: %1").arg (fi.filePath ());
return false;
}
if (! file_target.open (QIODevice::WriteOnly)) {
tl::error << QObject::tr ("Unable to open target file for writing: %1").arg (fi_target.filePath ());
return false;
}
size_t chunk_size = 64 * 1024;
while (! file.atEnd ()) {
QByteArray data = file.read (chunk_size);
file_target.write (data);
}
file.close ();
file_target.close ();
}
}
return true;
}

View File

@ -24,17 +24,57 @@
#define HDR_tlFileUtils
#include "tlCommon.h"
#include "tlString.h"
#include <QString>
namespace tl
{
/**
* @brief Returns a value indicating whether the parent path is a parent directory of the path
*/
bool TL_PUBLIC is_parent_path (const QString &parent, const QString &path);
/**
* @brief Returns a value indicating whether the parent path is a parent directory of the path (version with std::string)
*/
inline bool TL_PUBLIC is_parent_path (const std::string &parent, const std::string &path)
{
return is_parent_path (tl::to_qstring (parent), tl::to_qstring (path));
}
/**
* @brief Recursively remove the given directory, the files from that directory and all sub-directories
* @return True, if successful. False otherwise.
* @return True, if successful. false otherwise.
*/
bool TL_PUBLIC rm_dir_recursive (const QString &path);
/**
* @brief Recursively remove the given directory, the files from that directory and all sub-directories (version with std::string)
* @return True, if successful. false otherwise.
*/
inline bool TL_PUBLIC rm_dir_recursive (const std::string &path)
{
return rm_dir_recursive (tl::to_qstring (path));
}
/**
* @brief Recursively copies a given directory to a target directory
* Both target and source directories need to exist. New directories are created in the target
* directory if required.
* @return True, if successful. false otherwise.
*/
bool TL_PUBLIC cp_dir_recursive (const QString &source, const QString &target);
/**
* @brief Recursively remove the given directory, the files from that directory and all sub-directories (version with std::string)
* @return True, if successful. false otherwise.
*/
inline bool TL_PUBLIC cp_dir_recursive (const std::string &source, const std::string &target)
{
return cp_dir_recursive (tl::to_qstring (source), tl::to_qstring (target));
}
}
#endif

View File

@ -201,8 +201,6 @@ TEST (3)
QDir dir_cc (dir_c.filePath (QString::fromUtf8 ("c")));
QDir dir_ccv (dir_cc.filePath (QString::fromUtf8 ("v")));
tl_assert (tl::rm_dir_recursive (tmp_dir.path ()));
lay::SaltGrains gg;
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
EXPECT_EQ (gg.is_empty (), true);
@ -275,8 +273,6 @@ TEST (4)
QDir dir_cc (dir_c.filePath (QString::fromUtf8 ("c")));
QDir dir_ccv (dir_cc.filePath (QString::fromUtf8 ("v")));
tl_assert (tl::rm_dir_recursive (tmp_dir.path ()));
lay::SaltGrains gg;
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
EXPECT_EQ (gg.is_empty (), true);
@ -341,4 +337,8 @@ TEST (4)
salt.remove_location (tl::to_string (dir_c.path ()));
EXPECT_EQ (spy.count (), 0);
EXPECT_EQ (salt_to_string (salt), "[b,c/c/v,c/u]");
EXPECT_EQ (salt.grain_by_name ("x"), 0);
EXPECT_EQ (salt.grain_by_name ("b")->name (), "b");
EXPECT_EQ (salt.grain_by_name ("c/c/v")->name (), "c/c/v");
}

View File

@ -0,0 +1,155 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlFileUtils.h"
#include "utHead.h"
#include <QDir>
#include <QFileInfo>
#include <QFile>
TEST (1)
{
EXPECT_EQ (tl::is_parent_path (std::string ("/home"), "/home/matthias"), true);
EXPECT_EQ (tl::is_parent_path (std::string ("/home"), "/home"), true);
EXPECT_EQ (tl::is_parent_path (std::string (""), ""), true);
EXPECT_EQ (tl::is_parent_path (std::string ("/opt/klayout"), "/home/matthias"), false);
EXPECT_EQ (tl::is_parent_path (std::string ("/home/klayout"), "/home/matthias"), false);
}
TEST (2)
{
QDir tmp_dir = QFileInfo (tl::to_qstring (tmp_file ())).absoluteDir ();
tmp_dir.mkdir (QString::fromUtf8 ("a"));
QDir adir = tmp_dir;
adir.cd (QString::fromUtf8 ("a"));
EXPECT_EQ (adir.exists (), true);
EXPECT_EQ (tl::rm_dir_recursive (adir.absolutePath ()), true);
EXPECT_EQ (adir.exists (), false);
tmp_dir.mkdir (QString::fromUtf8 ("a"));
EXPECT_EQ (adir.exists (), true);
EXPECT_EQ (tl::rm_dir_recursive (tl::to_string (adir.absolutePath ())), true);
EXPECT_EQ (adir.exists (), false);
tmp_dir.mkdir (QString::fromUtf8 ("a"));
EXPECT_EQ (adir.exists (), true);
adir.mkdir (QString::fromUtf8 ("b1"));
QDir b1dir = adir;
b1dir.cd (QString::fromUtf8 ("b1"));
adir.mkdir (QString::fromUtf8 ("b2"));
QDir b2dir = adir;
b2dir.cd (QString::fromUtf8 ("b2"));
{
QFile file (b2dir.absoluteFilePath (QString::fromUtf8 ("x")));
file.open (QIODevice::WriteOnly);
file.write ("hello, world!\n");
file.close ();
}
{
QFile file (b2dir.absoluteFilePath (QString::fromUtf8 ("y")));
file.open (QIODevice::WriteOnly);
file.write ("hello, world!\n");
file.close ();
}
EXPECT_EQ (adir.exists (), true);
EXPECT_EQ (tl::rm_dir_recursive (adir.absolutePath ()), true);
EXPECT_EQ (adir.exists (), false);
EXPECT_EQ (b1dir.exists (), false);
EXPECT_EQ (b2dir.exists (), false);
EXPECT_EQ (QFileInfo (b2dir.absoluteFilePath (QString::fromUtf8 ("x"))).exists (), false);
}
TEST (3)
{
QDir tmp_dir = QFileInfo (tl::to_qstring (tmp_file ())).absoluteDir ();
tl::rm_dir_recursive (tmp_dir.filePath (QString::fromUtf8 ("a")));
tmp_dir.mkdir (QString::fromUtf8 ("a"));
QDir adir = tmp_dir;
adir.cd (QString::fromUtf8 ("a"));
adir.mkdir (QString::fromUtf8 ("b1"));
QDir b1dir = adir;
b1dir.cd (QString::fromUtf8 ("b1"));
adir.mkdir (QString::fromUtf8 ("b2"));
QDir b2dir = adir;
b2dir.cd (QString::fromUtf8 ("b2"));
{
QFile file (b2dir.absoluteFilePath (QString::fromUtf8 ("x")));
file.open (QIODevice::WriteOnly);
file.write ("hello, world!\n");
file.close ();
}
{
QFile file (b2dir.absoluteFilePath (QString::fromUtf8 ("y")));
file.open (QIODevice::WriteOnly);
file.write ("hello, world II!\n");
file.close ();
}
tl::rm_dir_recursive (tmp_dir.filePath (QString::fromUtf8 ("acopy")));
tmp_dir.mkdir (QString::fromUtf8 ("acopy"));
tl::cp_dir_recursive (tmp_dir.absoluteFilePath (QString::fromUtf8 ("a")), tmp_dir.absoluteFilePath (QString::fromUtf8 ("acopy")));
QDir acopydir = tmp_dir;
EXPECT_EQ (acopydir.cd (QString::fromUtf8 ("acopy")), true);
EXPECT_EQ (acopydir.exists (), true);
QDir b1copydir = acopydir;
EXPECT_EQ (b1copydir.cd (QString::fromUtf8 ("b1")), true);
EXPECT_EQ (b1copydir.exists (), true);
QDir b2copydir = acopydir;
EXPECT_EQ (b2copydir.cd (QString::fromUtf8 ("b2")), true);
EXPECT_EQ (b2copydir.exists (), true);
{
QFile file (b2copydir.absoluteFilePath (QString::fromUtf8 ("x")));
EXPECT_EQ (file.exists (), true);
file.open (QIODevice::ReadOnly);
EXPECT_EQ (file.readAll ().constData (), "hello, world!\n");
file.close ();
}
{
QFile file (b2copydir.absoluteFilePath (QString::fromUtf8 ("y")));
EXPECT_EQ (file.exists (), true);
file.open (QIODevice::ReadOnly);
EXPECT_EQ (file.readAll ().constData (), "hello, world II!\n");
file.close ();
}
}

View File

@ -96,7 +96,8 @@ SOURCES = \
tlXMLParser.cc \
gsiTest.cc \
tlFileSystemWatcher.cc \
laySalt.cc
laySalt.cc \
tlFileUtils.cc
# main components:
SOURCES += \

View File

@ -26,6 +26,7 @@
#include "pya.h"
#include "tlStaticObjects.h"
#include "tlTimer.h"
#include "tlFileUtils.h"
#include "layApplication.h"
#include "gsiExpression.h"
#include "gsiExternalMain.h"
@ -518,8 +519,12 @@ bool TestBase::do_test (const std::string & /*mode*/)
{
// Ensures the test temp directory is present
QDir dir (testtmp ());
QDir tmpdir (dir.absoluteFilePath (tl::to_qstring (m_testdir)));
if (tmpdir.exists () && ! tl::rm_dir_recursive (tmpdir.absolutePath ())) {
throw tl::Exception ("Unable to clean temporary dir: " + tl::to_string (tmpdir.absolutePath ()));
}
if (! dir.mkpath (tl::to_qstring (m_testdir))) {
throw tl::Exception ("Unable to create path for temporary files: " + tl::to_string (dir.filePath (tl::to_qstring (m_test))));
throw tl::Exception ("Unable to create path for temporary files: " + tl::to_string (tmpdir.absolutePath ()));
}
dir.cd (tl::to_qstring (m_testdir));