mirror of https://github.com/KLayout/klayout.git
WIP: checking of grain properties.
This commit is contained in:
parent
ec415d9251
commit
334fca3f76
|
|
@ -185,6 +185,48 @@ SaltGrain::compare_versions (const std::string &v1, const std::string &v2)
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
SaltGrain::spec_url (const std::string &url)
|
||||
{
|
||||
std::string res = url;
|
||||
if (! res.empty()) {
|
||||
if (res [res.size () - 1] != '/') {
|
||||
res += "/";
|
||||
}
|
||||
res += grain_filename;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
SaltGrain::valid_name (const std::string &n)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
tl::Extractor ex (n);
|
||||
|
||||
std::string s;
|
||||
if (! ex.try_read_word (s, "_")) {
|
||||
return false;
|
||||
}
|
||||
res += s;
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
if (! ex.test ("/")) {
|
||||
return false;
|
||||
}
|
||||
if (! ex.try_read_word (s, "_")) {
|
||||
return false;
|
||||
}
|
||||
res += "/";
|
||||
res += s;
|
||||
}
|
||||
|
||||
// this captures the cases where the extractor skips blanks
|
||||
// TODO: the extractor should have a "non-blank-skipping" mode
|
||||
return s == n;
|
||||
}
|
||||
|
||||
bool
|
||||
SaltGrain::valid_version (const std::string &v)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -357,6 +357,11 @@ public:
|
|||
*/
|
||||
static bool valid_version (const std::string &v);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the given string is a valid name
|
||||
*/
|
||||
static bool valid_name (const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Detects a grain from the given directory
|
||||
* This method will return a grain constructed from the given directory.
|
||||
|
|
@ -365,6 +370,11 @@ public:
|
|||
*/
|
||||
static SaltGrain from_path (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Forms the spec file download URL from a given download URL
|
||||
*/
|
||||
static std::string spec_url (const std::string &url);
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the given path represents is a grain
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "laySalt.h"
|
||||
#include "tlString.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlHttpStream.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
|
|
@ -34,6 +35,8 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -397,29 +400,173 @@ SaltGrainPropertiesDialog::remove_dependency_clicked ()
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class DependencyGraph
|
||||
{
|
||||
public:
|
||||
DependencyGraph (Salt *salt)
|
||||
{
|
||||
for (lay::Salt::flat_iterator i = salt->begin_flat (); i != salt->end_flat (); ++i) {
|
||||
m_name_to_grain.insert (std::make_pair ((*i)->name (), *i));
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid_name (const std::string &name) const
|
||||
{
|
||||
return m_name_to_grain.find (name) != m_name_to_grain.end ();
|
||||
}
|
||||
|
||||
const lay::SaltGrain *grain_for_name (const std::string &name) const
|
||||
{
|
||||
std::map <std::string, const lay::SaltGrain *>::const_iterator n = m_name_to_grain.find (name);
|
||||
if (n != m_name_to_grain.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void check_circular (const lay::SaltGrain *current, const lay::SaltGrain *new_dep)
|
||||
{
|
||||
std::vector <const lay::SaltGrain *> path;
|
||||
path.push_back (current);
|
||||
check_circular_follow (new_dep, path);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map <std::string, const lay::SaltGrain *> m_name_to_grain;
|
||||
|
||||
void check_circular_follow (const lay::SaltGrain *current, std::vector <const lay::SaltGrain *> &path)
|
||||
{
|
||||
if (! current) {
|
||||
return;
|
||||
}
|
||||
|
||||
path.push_back (current);
|
||||
|
||||
for (std::vector <const lay::SaltGrain *>::const_iterator p = path.begin (); p != path.end () - 1; ++p) {
|
||||
if (*p == current) {
|
||||
circular_reference_error (path);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<SaltGrain::Dependency>::const_iterator d = current->dependencies ().begin (); d != current->dependencies ().end (); ++d) {
|
||||
check_circular_follow (grain_for_name (d->name), path);
|
||||
}
|
||||
|
||||
path.pop_back ();
|
||||
}
|
||||
|
||||
void circular_reference_error (std::vector <const lay::SaltGrain *> &path)
|
||||
{
|
||||
std::string msg = tl::to_string (QObject::tr ("The following path forms a circular dependency: "));
|
||||
for (std::vector <const lay::SaltGrain *>::const_iterator p = path.begin (); p != path.end (); ++p) {
|
||||
if (p != path.begin ()) {
|
||||
msg += "->";
|
||||
}
|
||||
msg += (*p)->name ();
|
||||
}
|
||||
throw tl::Exception (msg);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SaltGrainPropertiesDialog::accept ()
|
||||
{
|
||||
update_data ();
|
||||
|
||||
// Perform some checks
|
||||
|
||||
// license
|
||||
license_alert->clear ();
|
||||
if (m_grain.license ().empty ()) {
|
||||
license_alert->warn () << tr ("License field is empty. Please consider specifying a license model.");
|
||||
license_alert->warn () << tr ("License field is empty. Please consider specifying a license model.") << tl::endl
|
||||
<< tr ("A license model tells users whether and how to use the source code of the package.");
|
||||
}
|
||||
|
||||
// version
|
||||
version_alert->clear ();
|
||||
if (m_grain.version ().empty ()) {
|
||||
version_alert->warn () << tr ("Version field is empty. Please consider specifying a version number.");
|
||||
version_alert->warn () << tr ("Version field is empty. Please consider specifying a version number.") << tl::endl
|
||||
<< tr ("Versions help the system to apply upgrades if required.");
|
||||
} else if (! SaltGrain::valid_version (m_grain.version ())) {
|
||||
version_alert->error () << tr ("'%1' is not a valid version string. A version string needs to be numeric (like '1.2.3' or '4.5'').").arg (tl::to_qstring (m_grain.version ()));
|
||||
}
|
||||
|
||||
// doc URL
|
||||
doc_url_alert->clear ();
|
||||
// @@@ TODO
|
||||
if (! m_grain.doc_url ().empty ()) {
|
||||
tl::InputHttpStream stream (m_grain.doc_url ());
|
||||
try {
|
||||
char b;
|
||||
stream.read (&b, 1);
|
||||
} catch (tl::Exception &ex) {
|
||||
doc_url_alert->error () << tr ("Attempt to read documentation URL failed. Error details follow.") << tl::endl
|
||||
<< tr ("URL: ") << m_grain.doc_url () << tl::endl
|
||||
<< tr ("Message: ") << ex.msg ();
|
||||
}
|
||||
}
|
||||
|
||||
// dependencies
|
||||
dependencies_alert->clear ();
|
||||
// @@@ TODO
|
||||
DependencyGraph dep (mp_salt);
|
||||
std::set <std::string> dep_seen;
|
||||
for (std::vector<SaltGrain::Dependency>::const_iterator d = m_grain.dependencies ().begin (); d != m_grain.dependencies ().end (); ++d) {
|
||||
|
||||
if (! SaltGrain::valid_name (d->name)) {
|
||||
dependencies_alert->error () << tr ("'%1' is not a valid package name").arg (tl::to_qstring (d->name)) << tl::endl
|
||||
<< tr ("Valid package names are words (letters, digits, underscores)") << tl::endl
|
||||
<< tr ("Package groups can be specified in the form 'group/package'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dep_seen.find (d->name) != dep_seen.end ()) {
|
||||
dependencies_alert->error () << tr ("Duplicate dependency '%1'").arg (tl::to_qstring (d->name)) << tl::endl
|
||||
<< tr ("A package cannot be dependent on the same package twice. Remove on entry.");
|
||||
continue;
|
||||
}
|
||||
dep_seen.insert (d->name);
|
||||
|
||||
if (! dep.is_valid_name (d->name)) {
|
||||
dependencies_alert->warn () << tr ("'%1' is not a name of a package loaded already").arg (tl::to_qstring (d->name)) << tl::endl
|
||||
<< tr ("You need to specify the details (version, URL) manually");
|
||||
} else {
|
||||
try {
|
||||
dep.check_circular (dep.grain_for_name (m_grain.name ()), dep.grain_for_name (d->name));
|
||||
} catch (tl::Exception &ex) {
|
||||
dependencies_alert->error () << ex.msg () << tl::endl
|
||||
<< tr ("Circular dependency means a package is eventually depending on itself.");
|
||||
}
|
||||
}
|
||||
|
||||
if (d->version.empty ()) {
|
||||
dependencies_alert->warn () << tr ("No version specified for dependency '%1'").arg (tl::to_qstring (d->name)) << tl::endl
|
||||
<< tr ("Versions help checking dependencies.") << tl::endl
|
||||
<< tr ("If the dependency package has a version itself, the version is automatically set to it's current version");
|
||||
}
|
||||
|
||||
if (d->url.empty ()) {
|
||||
dependencies_alert->warn () << tr ("No download URL specified for dependency '%1'").arg (tl::to_qstring (d->name)) << tl::endl
|
||||
<< tr ("A download URL should be specified to ensure the package dependencies can be resolved.") << tl::endl
|
||||
<< tr ("If the dependency package was downloaded itself, the URL is automatically set to the download source");
|
||||
} else {
|
||||
std::string spec_url = SaltGrain::spec_url (d->url);
|
||||
tl::InputHttpStream stream (spec_url);
|
||||
try {
|
||||
char b;
|
||||
stream.read (&b, 1);
|
||||
} catch (tl::Exception &ex) {
|
||||
dependencies_alert->error () << tr ("Attempt to read download URL failed. Error details follow.") << tl::endl
|
||||
<< tr ("URL: ") << spec_url << tl::endl
|
||||
<< tr ("Message: ") << ex.msg ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!license_alert->needs_attention () &&
|
||||
!doc_url_alert->needs_attention () &&
|
||||
|
|
|
|||
Loading…
Reference in New Issue