mirror of https://github.com/KLayout/klayout.git
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:
parent
10345eea73
commit
820c291623
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ SaltManagerDialog::current_changed ()
|
|||
} else {
|
||||
details_frame->setEnabled (true);
|
||||
delete_button->setEnabled (true);
|
||||
edit_button->setEnabled (! g->is_readonly ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,8 @@ SOURCES = \
|
|||
tlXMLParser.cc \
|
||||
gsiTest.cc \
|
||||
tlFileSystemWatcher.cc \
|
||||
laySalt.cc
|
||||
laySalt.cc \
|
||||
tlFileUtils.cc
|
||||
|
||||
# main components:
|
||||
SOURCES += \
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue