Do basic sanity check of a package's most important fields when checking for problems
This commit is contained in:
parent
77000ac7d3
commit
524b16815a
|
@ -443,6 +443,84 @@ bool Package::isArchAny() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool containsUnexpectedCharacters(std::string_view value)
|
||||||
|
{
|
||||||
|
for (auto c : value) {
|
||||||
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
case '.':
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool containsUnprintableCharacters(std::string_view value)
|
||||||
|
{
|
||||||
|
for (auto c : value) {
|
||||||
|
if (c < ' ' || c >= 127) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_FIELD_EMPTY(field) \
|
||||||
|
if (field.empty()) { \
|
||||||
|
problems.emplace_back(#field " is empty"); \
|
||||||
|
}
|
||||||
|
#define CHECK_FIELD_FOR_UNEXPECTED_CHARS(field) \
|
||||||
|
if (containsUnexpectedCharacters(field)) { \
|
||||||
|
problems.emplace_back(#field " contains unexpected characters"); \
|
||||||
|
}
|
||||||
|
#define CHECK_FIELD_FOR_UNPRINTABLE_CHARS(field) \
|
||||||
|
if (containsUnprintableCharacters(field)) { \
|
||||||
|
problems.emplace_back(#field " contains unprintable or non-ASCII characters"); \
|
||||||
|
}
|
||||||
|
#define CHECK_FIELD_STRICT(field) \
|
||||||
|
CHECK_FIELD_EMPTY(field) \
|
||||||
|
CHECK_FIELD_FOR_UNEXPECTED_CHARS(field)
|
||||||
|
#define CHECK_FIELD_RELAXED(field) \
|
||||||
|
CHECK_FIELD_EMPTY(field) \
|
||||||
|
CHECK_FIELD_FOR_UNPRINTABLE_CHARS(field)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Performs a basic sanity check of the package's fields.
|
||||||
|
* \returns Returns an empty vector if no problems were found; otherwise returns the problem descriptions.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> Package::validate() const
|
||||||
|
{
|
||||||
|
// check basic fields
|
||||||
|
auto problems = std::vector<std::string>();
|
||||||
|
CHECK_FIELD_STRICT(name)
|
||||||
|
CHECK_FIELD_RELAXED(version)
|
||||||
|
CHECK_FIELD_STRICT(arch)
|
||||||
|
|
||||||
|
// check dependencies
|
||||||
|
const auto checkDeps = sourceInfo ? sourceInfo->checkDependencies : std::vector<Dependency>();
|
||||||
|
const auto makeDeps = sourceInfo ? sourceInfo->makeDependencies : std::vector<Dependency>();
|
||||||
|
for (const auto &deps : { dependencies, optionalDependencies, provides, conflicts, replaces, checkDeps, makeDeps }) {
|
||||||
|
for (const auto &dep : deps) {
|
||||||
|
if (dep.name.empty()) {
|
||||||
|
problems.emplace_back("dependency is empty");
|
||||||
|
return problems;
|
||||||
|
}
|
||||||
|
if (containsUnexpectedCharacters(dep.name)) {
|
||||||
|
problems.emplace_back("dependency contains unexpected characters");
|
||||||
|
return problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return problems;
|
||||||
|
}
|
||||||
|
|
||||||
DependencySetBase::iterator DependencySet::find(const Dependency &dependency)
|
DependencySetBase::iterator DependencySet::find(const Dependency &dependency)
|
||||||
{
|
{
|
||||||
for (auto range = equal_range(dependency.name); range.first != range.second; ++range.first) {
|
for (auto range = equal_range(dependency.name); range.first != range.second; ++range.first) {
|
||||||
|
|
|
@ -417,6 +417,7 @@ struct LIBPKG_EXPORT Package : public PackageBase,
|
||||||
std::vector<std::string> processDllsReferencedByImportLibs(std::set<std::string> &&dllsReferencedByImportLibs);
|
std::vector<std::string> processDllsReferencedByImportLibs(std::set<std::string> &&dllsReferencedByImportLibs);
|
||||||
bool addDepsAndProvidesFromOtherPackage(const Package &otherPackage, bool force = false);
|
bool addDepsAndProvidesFromOtherPackage(const Package &otherPackage, bool force = false);
|
||||||
bool isArchAny() const;
|
bool isArchAny() const;
|
||||||
|
std::vector<std::string> validate() const;
|
||||||
using ReflectiveRapidJSON::JsonSerializable<Package>::fromJson;
|
using ReflectiveRapidJSON::JsonSerializable<Package>::fromJson;
|
||||||
using ReflectiveRapidJSON::JsonSerializable<Package>::toJson;
|
using ReflectiveRapidJSON::JsonSerializable<Package>::toJson;
|
||||||
using ReflectiveRapidJSON::JsonSerializable<Package>::toJsonDocument;
|
using ReflectiveRapidJSON::JsonSerializable<Package>::toJsonDocument;
|
||||||
|
|
|
@ -466,6 +466,10 @@ void CheckForProblems::run()
|
||||||
RepositoryProblem{ .desc = "configured local package directory \"" % db->localPkgDir + "\" is not a directory" });
|
RepositoryProblem{ .desc = "configured local package directory \"" % db->localPkgDir + "\" is not a directory" });
|
||||||
}
|
}
|
||||||
db->allPackages([&](LibPkg::StorageID, std::shared_ptr<LibPkg::Package> &&package) {
|
db->allPackages([&](LibPkg::StorageID, std::shared_ptr<LibPkg::Package> &&package) {
|
||||||
|
const auto packageProblems = package->validate();
|
||||||
|
for (const auto &problem : packageProblems) {
|
||||||
|
problems.emplace_back(RepositoryProblem{ .desc = problem, .pkg = package->name });
|
||||||
|
}
|
||||||
if (!package->packageInfo) {
|
if (!package->packageInfo) {
|
||||||
problems.emplace_back(RepositoryProblem{ .desc = "no package info present", .pkg = package->name });
|
problems.emplace_back(RepositoryProblem{ .desc = "no package info present", .pkg = package->name });
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue