1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2019 Jochen Ulrich <jochenulrich@t-online.de>
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qbs.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #ifndef QBS_BUILDGRAPH_COMMAND_H
42 #define QBS_BUILDGRAPH_COMMAND_H
43 
44 #include "forward_decls.h"
45 
46 #include <tools/codelocation.h>
47 #include <tools/persistence.h>
48 #include <tools/set.h>
49 
50 #include <QtCore/qprocess.h>
51 #include <QtCore/qstringlist.h>
52 #include <QtCore/qvariant.h>
53 
54 #include <QtScript/qscriptvalue.h>
55 
56 namespace qbs {
57 namespace Internal {
58 
59 class AbstractCommand
60 {
61 public:
62     virtual ~AbstractCommand();
63 
64     enum CommandType {
65         ProcessCommandType,
66         JavaScriptCommandType
67     };
68 
defaultDescription()69     static QString defaultDescription() { return {}; }
defaultExtendedDescription()70     static QString defaultExtendedDescription() { return {}; }
defaultHighLight()71     static QString defaultHighLight() { return {}; }
defaultIgnoreDryRun()72     static bool defaultIgnoreDryRun() { return false; }
defaultIsSilent()73     static bool defaultIsSilent() { return false; }
defaultTimeout()74     static int defaultTimeout() { return -1; }
75 
76     virtual CommandType type() const = 0;
77     virtual bool equals(const AbstractCommand *other) const;
78     virtual void fillFromScriptValue(const QScriptValue *scriptValue, const CodeLocation &codeLocation);
79 
80     QString fullDescription(const QString &productName) const;
description()81     const QString description() const { return m_description; }
extendedDescription()82     const QString extendedDescription() const { return m_extendedDescription; }
highlight()83     const QString highlight() const { return m_highlight; }
ignoreDryRun()84     bool ignoreDryRun() const { return m_ignoreDryRun; }
isSilent()85     bool isSilent() const { return m_silent; }
jobPool()86     QString jobPool() const { return m_jobPool; }
codeLocation()87     CodeLocation codeLocation() const { return m_codeLocation; }
timeout()88     int timeout() const { return m_timeout; }
89 
properties()90     const QVariantMap &properties() const { return m_properties; }
91 
92     virtual void load(PersistentPool &pool);
93     virtual void store(PersistentPool &pool);
94 
95 protected:
96     AbstractCommand();
97     void applyCommandProperties(const QScriptValue *scriptValue);
98 
99     Set<QString> m_predefinedProperties;
100 
101 private:
serializationOp(PersistentPool & pool)102     template<PersistentPool::OpType opType> void serializationOp(PersistentPool &pool)
103     {
104         pool.serializationOp<opType>(m_description, m_extendedDescription, m_highlight,
105                                      m_ignoreDryRun, m_silent, m_codeLocation, m_jobPool,
106                                      m_timeout, m_properties);
107     }
108 
109     QString m_description;
110     QString m_extendedDescription;
111     QString m_highlight;
112     bool m_ignoreDryRun;
113     bool m_silent;
114     CodeLocation m_codeLocation;
115     QString m_jobPool;
116     int m_timeout;
117     QVariantMap m_properties;
118 };
119 
120 class ProcessCommand : public AbstractCommand
121 {
122 public:
create()123     static ProcessCommandPtr create() { return ProcessCommandPtr(new ProcessCommand); }
124     static void setupForJavaScript(QScriptValue targetObject);
125 
type()126     CommandType type() const override { return ProcessCommandType; }
127     bool equals(const AbstractCommand *otherAbstractCommand) const override;
128     void fillFromScriptValue(const QScriptValue *scriptValue,
129                              const CodeLocation &codeLocation) override;
program()130     const QString program() const { return m_program; }
arguments()131     const QStringList arguments() const { return m_arguments; }
workingDir()132     const QString workingDir() const { return m_workingDir; }
maxExitCode()133     int maxExitCode() const { return m_maxExitCode; }
stdoutFilterFunction()134     QString stdoutFilterFunction() const { return m_stdoutFilterFunction; }
stderrFilterFunction()135     QString stderrFilterFunction() const { return m_stderrFilterFunction; }
responseFileThreshold()136     int responseFileThreshold() const { return m_responseFileThreshold; }
responseFileArgumentIndex()137     int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; }
responseFileUsagePrefix()138     QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; }
responseFileSeparator()139     QString responseFileSeparator() const { return m_responseFileSeparator; }
environment()140     QProcessEnvironment environment() const { return m_environment; }
141     QStringList relevantEnvVars() const;
clearRelevantEnvValues()142     void clearRelevantEnvValues() { m_relevantEnvValues.clear(); }
143     void addRelevantEnvValue(const QString &key, const QString &value);
relevantEnvValue(const QString & key)144     QString relevantEnvValue(const QString &key) const { return m_relevantEnvValues.value(key); }
stdoutFilePath()145     QString stdoutFilePath() const { return m_stdoutFilePath; }
stderrFilePath()146     QString stderrFilePath() const { return m_stderrFilePath; }
147 
148     void load(PersistentPool &pool) override;
149     void store(PersistentPool &pool) override;
150 
151 private:
152     ProcessCommand();
153 
154     int defaultResponseFileThreshold() const;
155 
156     void getEnvironmentFromList(const QStringList &envList);
157 
serializationOp(PersistentPool & pool)158     template<PersistentPool::OpType opType> void serializationOp(PersistentPool &pool)
159     {
160         pool.serializationOp<opType>(m_program, m_arguments, m_environment, m_workingDir,
161                                      m_stdoutFilterFunction, m_stderrFilterFunction,
162                                      m_responseFileUsagePrefix, m_responseFileSeparator,
163                                      m_maxExitCode, m_responseFileThreshold,
164                                      m_responseFileArgumentIndex, m_relevantEnvVars,
165                                      m_relevantEnvValues, m_stdoutFilePath, m_stderrFilePath);
166     }
167 
168     QString m_program;
169     QStringList m_arguments;
170     QString m_workingDir;
171     int m_maxExitCode;
172     QString m_stdoutFilterFunction;
173     QString m_stderrFilterFunction;
174     int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments).
175     int m_responseFileArgumentIndex;
176     QString m_responseFileUsagePrefix;
177     QString m_responseFileSeparator;
178     QProcessEnvironment m_environment;
179     QStringList m_relevantEnvVars;
180     QProcessEnvironment m_relevantEnvValues;
181     QString m_stdoutFilePath;
182     QString m_stderrFilePath;
183 };
184 
185 class JavaScriptCommand : public AbstractCommand
186 {
187 public:
create()188     static JavaScriptCommandPtr create() { return JavaScriptCommandPtr(new JavaScriptCommand); }
189     static void setupForJavaScript(QScriptValue targetObject);
190 
type()191     CommandType type() const override { return JavaScriptCommandType; }
192     bool equals(const AbstractCommand *otherAbstractCommand) const override;
193     void fillFromScriptValue(const QScriptValue *scriptValue,
194                              const CodeLocation &codeLocation) override;
195 
scopeName()196     const QString &scopeName() const { return m_scopeName; }
sourceCode()197     const QString &sourceCode() const { return m_sourceCode; }
setSourceCode(const QString & str)198     void setSourceCode(const QString &str) { m_sourceCode = str; }
199 
200     void load(PersistentPool &pool) override;
201     void store(PersistentPool &pool) override;
202 
203 private:
204     JavaScriptCommand();
205 
serializationOp(PersistentPool & pool)206     template<PersistentPool::OpType opType> void serializationOp(PersistentPool &pool)
207     {
208         pool.serializationOp<opType>(m_scopeName, m_sourceCode);
209     }
210 
211     QString m_scopeName;
212     QString m_sourceCode;
213 };
214 
215 class CommandList
216 {
217 public:
empty()218     bool empty() const { return m_commands.empty(); }
size()219     int size() const { return m_commands.size(); }
commandAt(int i)220     AbstractCommandPtr commandAt(int i) const { return m_commands.at(i); }
commands()221     const QList<AbstractCommandPtr> &commands() const { return m_commands; }
222 
clear()223     void clear() { m_commands.clear(); }
addCommand(const AbstractCommandPtr & cmd)224     void addCommand(const AbstractCommandPtr &cmd) { m_commands.push_back(cmd); }
225 
226     void load(PersistentPool &pool);
227     void store(PersistentPool &pool) const;
228 private:
229     QList<AbstractCommandPtr> m_commands;
230 };
231 bool operator==(const CommandList &cl1, const CommandList &cl2);
232 inline bool operator!=(const CommandList &cl1, const CommandList &cl2) { return !(cl1 == cl2); }
233 
234 } // namespace Internal
235 } // namespace qbs
236 
237 #endif // QBS_BUILDGRAPH_COMMAND_H
238