productmapping.cpp 6.86 KB
Newer Older
1
2
/*******************************************************************
* productmapping.cpp
3
* SPDX-FileCopyrightText: 2009 Dario Andres Rodriguez <andresbajotierra@gmail.com>
4
*
5
* SPDX-License-Identifier: GPL-2.0-or-later
6
7
8
9
10
11
12
*
******************************************************************/

#include "productmapping.h"

#include <KConfig>
#include <KConfigGroup>
Laurent Montel's avatar
Laurent Montel committed
13
#include "drkonqi_debug.h"
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <QStandardPaths>

#include "bugzillalib.h"
#include "crashedapplication.h"

ProductMapping::ProductMapping(const CrashedApplication * crashedApp, BugzillaManager * bzManager, QObject * parent)
    : QObject(parent)
    , m_crashedAppPtr(crashedApp)
    , m_bugzillaManagerPtr(bzManager)
    , m_bugzillaProductDisabled(false)
    , m_bugzillaVersionDisabled(false)

{
    //Default "fallback" values
    m_bugzillaProduct = crashedApp->fakeExecutableBaseName();
Laurent Montel's avatar
Laurent Montel committed
29
30
    m_bugzillaComponent = QStringLiteral("general");
    m_bugzillaVersionString = QStringLiteral("unspecified");
31
32
33
34
35
    m_relatedBugzillaProducts = QStringList() << m_bugzillaProduct;

    map(crashedApp->fakeExecutableBaseName());

    //Get valid versions
36
    connect(m_bugzillaManagerPtr, &BugzillaManager::productInfoFetched, this, &ProductMapping::checkProductInfo);
37
38
39
40
41
42
43
44
45
46
47
48

    m_bugzillaManagerPtr->fetchProductInfo(m_bugzillaProduct);
}

void ProductMapping::map(const QString & appName)
{
    mapUsingInternalFile(appName);
    getRelatedProductsUsingInternalFile(m_bugzillaProduct);
}

void ProductMapping::mapUsingInternalFile(const QString & appName)
{
49
    KConfig mappingsFile(QString::fromLatin1("mappings"), KConfig::NoGlobals, QStandardPaths::AppDataLocation);
50
51
52
53
    const KConfigGroup mappings = mappingsFile.group("Mappings");
    if (mappings.hasKey(appName)) {
        QString mappingString = mappings.readEntry(appName);
        if (!mappingString.isEmpty()) {
54
            QStringList list = mappingString.split(QLatin1Char('|'), Qt::SkipEmptyParts);
55
56
57
58
59
            if (list.count()==2) {
                m_bugzillaProduct = list.at(0);
                m_bugzillaComponent = list.at(1);
                m_relatedBugzillaProducts = QStringList() << m_bugzillaProduct;
            } else {
Laurent Montel's avatar
Laurent Montel committed
60
                qCWarning(DRKONQI_LOG) << "Error while reading mapping entry. Sections found " << list.count();
61
62
            }
        } else {
Laurent Montel's avatar
Laurent Montel committed
63
            qCWarning(DRKONQI_LOG) << "Error while reading mapping entry. Entry exists but it is empty "
64
65
66
67
68
69
70
71
72
73
                            "(or there was an error when reading)";
        }
    }
}

void ProductMapping::getRelatedProductsUsingInternalFile(const QString & bugzillaProduct)
{
    //ProductGroup ->  kontact=kdepim
    //Groups -> kdepim=kontact|kmail|korganizer|akonadi|pimlibs..etc

74
    KConfig mappingsFile(QString::fromLatin1("mappings"), KConfig::NoGlobals, QStandardPaths::AppDataLocation);
75
76
77
78
79
80
81
    const KConfigGroup productGroup = mappingsFile.group("ProductGroup");

    //Get groups of the application
    QStringList groups;
    if (productGroup.hasKey(bugzillaProduct)) {
        QString group = productGroup.readEntry(bugzillaProduct);
        if (group.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
82
            qCWarning(DRKONQI_LOG) << "Error while reading mapping entry. Entry exists but it is empty "
83
84
85
                            "(or there was an error when reading)";
            return;
        }
86
        groups = group.split(QLatin1Char('|'), Qt::SkipEmptyParts);
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    }

    //All KDE apps use the KDE Platform (basic libs)
    groups << QLatin1String("kdeplatform");

    //Add the product itself
    m_relatedBugzillaProducts = QStringList() << m_bugzillaProduct;

    //Get related products of each related group
    Q_FOREACH( const QString & group, groups ) {
        const KConfigGroup bzGroups = mappingsFile.group("BZGroups");
        if (bzGroups.hasKey(group)) {
            QString bzGroup = bzGroups.readEntry(group);
            if (!bzGroup.isEmpty()) {
101
                QStringList relatedGroups = bzGroup.split(QLatin1Char('|'), Qt::SkipEmptyParts);
102
103
104
105
                if (relatedGroups.size()>0) {
                    m_relatedBugzillaProducts.append(relatedGroups);
                }
            } else {
Laurent Montel's avatar
Laurent Montel committed
106
                qCWarning(DRKONQI_LOG) << "Error while reading mapping entry. Entry exists but it is empty "
107
108
109
110
111
112
                                "(or there was an error when reading)";
            }
        }
    }
}

Harald Sitter's avatar
Harald Sitter committed
113
void ProductMapping::checkProductInfo(const Bugzilla::Product::Ptr product)
114
115
116
{
    // check whether the product itself is disabled for new reports,
    // which usually means that product/application is unmaintained.
Harald Sitter's avatar
Harald Sitter committed
117
    m_bugzillaProductDisabled = !product->isActive();
118
119

    // check whether the product on bugzilla contains the expected component
Harald Sitter's avatar
Harald Sitter committed
120
    if (!product->componentNames().contains(m_bugzillaComponent)) {
121
122
123
124
125
        m_bugzillaComponent = QLatin1String("general");
    }

    // find the appropriate version to use on bugzilla
    const QString version = m_crashedAppPtr->version();
Harald Sitter's avatar
Harald Sitter committed
126
    const QStringList &allVersions = product->allVersions();
127
128
129
130
131
132
133
134
135
136

    if (allVersions.contains(version)) {
        //The version the crash application provided is a valid bugzilla version: use it !
        m_bugzillaVersionString = version;
    } else if (version.endsWith(QLatin1String(".00"))) {
        //check if there is a version on bugzilla with just ".0"
        const QString shorterVersion = version.left(version.size() - 1);
        if (allVersions.contains(shorterVersion)) {
            m_bugzillaVersionString = shorterVersion;
        }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    } else if (!allVersions.contains(m_bugzillaVersionString)) {
        // No good match found, make sure the default is sound...
        // If our hardcoded fallback is not in bugzilla it was likely
        // renamed so we'll find the version with the lowest id instead
        // and that should technically have been the "default" version.
        Bugzilla::ProductVersion *lowestVersion = nullptr;
        for (const auto &version : product->versions()) {
            if (!lowestVersion || lowestVersion->id() > version->id()) {
                lowestVersion = version;
            }
        }
        if (lowestVersion) {
            m_bugzillaVersionString = lowestVersion->name();
        }
151
152
    }

Yuri Chornoivan's avatar
Yuri Chornoivan committed
153
    // check whether that versions is disabled for new reports, which
154
    // usually means that version is outdated and not supported anymore.
Harald Sitter's avatar
Harald Sitter committed
155
    const QStringList &inactiveVersions = product->inactiveVersions();
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    m_bugzillaVersionDisabled = inactiveVersions.contains(m_bugzillaVersionString);
}

QStringList ProductMapping::relatedBugzillaProducts() const
{
    return m_relatedBugzillaProducts;
}

QString ProductMapping::bugzillaProduct() const
{
    return m_bugzillaProduct;
}

QString ProductMapping::bugzillaComponent() const
{
    return m_bugzillaComponent;
}

QString ProductMapping::bugzillaVersion() const
{
    return m_bugzillaVersionString;
}

bool ProductMapping::bugzillaProductDisabled() const
{
    return m_bugzillaProductDisabled;
}

bool ProductMapping::bugzillaVersionDisabled() const
{
    return m_bugzillaVersionDisabled;
}