1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "processparameters.h"
27
28 #include <utils/fileutils.h>
29 #include <utils/macroexpander.h>
30 #include <utils/qtcprocess.h>
31 #include <utils/theme/theme.h>
32
33 #include <QDir>
34
35 /*!
36 \class ProjectExplorer::ProcessParameters
37
38 \brief The ProcessParameters class aggregates all parameters needed to start
39 a process.
40
41 It offers a set of functions which expand macros and environment variables
42 inside the raw parameters to obtain final values for starting a process
43 or for display purposes.
44
45 \sa ProjectExplorer::AbstractProcessStep
46 */
47
48 using namespace Utils;
49
50 namespace ProjectExplorer {
51
52 ProcessParameters::ProcessParameters() = default;
53
54 /*!
55 Sets the command to run.
56 */
setCommandLine(const CommandLine & cmdLine)57 void ProcessParameters::setCommandLine(const CommandLine &cmdLine)
58 {
59 m_command = cmdLine;
60 m_effectiveCommand.clear();
61 m_effectiveArguments.clear();
62
63 effectiveCommand();
64 effectiveArguments();
65 }
66
67 /*!
68 Sets the \a workingDirectory for the process for a build configuration.
69
70 Should be called from init().
71 */
72
setWorkingDirectory(const FilePath & workingDirectory)73 void ProcessParameters::setWorkingDirectory(const FilePath &workingDirectory)
74 {
75 m_workingDirectory = workingDirectory;
76 m_effectiveWorkingDirectory.clear();
77
78 effectiveWorkingDirectory();
79 }
80
81 /*!
82 \fn void ProjectExplorer::ProcessParameters::setEnvironment(const Utils::Environment &env)
83 Sets the environment \a env for running the command.
84
85 Should be called from init().
86 */
87
88 /*!
89 \fn void ProjectExplorer::ProcessParameters::setMacroExpander(Utils::MacroExpander *mx)
90 Sets the macro expander \a mx to use on the command, arguments, and working
91 dir.
92
93 \note The caller retains ownership of the object.
94 */
95
96 /*!
97 Gets the fully expanded working directory.
98 */
99
effectiveWorkingDirectory() const100 FilePath ProcessParameters::effectiveWorkingDirectory() const
101 {
102 if (m_effectiveWorkingDirectory.isEmpty()) {
103 m_effectiveWorkingDirectory = m_workingDirectory;
104 QString path = m_workingDirectory.path();
105 if (m_macroExpander)
106 path = m_macroExpander->expand(path);
107 m_effectiveWorkingDirectory.setPath(QDir::cleanPath(m_environment.expandVariables(path)));
108 }
109 return m_effectiveWorkingDirectory;
110 }
111
112 /*!
113 Gets the fully expanded command name to run.
114 */
115
effectiveCommand() const116 FilePath ProcessParameters::effectiveCommand() const
117 {
118 if (m_effectiveCommand.isEmpty()) {
119 FilePath cmd = m_command.executable();
120 if (m_macroExpander)
121 cmd = m_macroExpander->expand(cmd);
122 if (cmd.needsDevice()) {
123 // Assume this is already good. FIXME: It is possibly not, so better fix searchInPath.
124 m_effectiveCommand = cmd;
125 } else {
126 m_effectiveCommand = m_environment.searchInPath(cmd.toString(),
127 {effectiveWorkingDirectory()});
128 }
129 m_commandMissing = m_effectiveCommand.isEmpty();
130 if (m_commandMissing)
131 m_effectiveCommand = cmd;
132 }
133 return m_effectiveCommand;
134 }
135
136 /*!
137 Returns \c true if effectiveCommand() would return only a fallback.
138 */
139
commandMissing() const140 bool ProcessParameters::commandMissing() const
141 {
142 effectiveCommand();
143 return m_commandMissing;
144 }
145
effectiveArguments() const146 QString ProcessParameters::effectiveArguments() const
147 {
148 if (m_effectiveArguments.isEmpty()) {
149 m_effectiveArguments = m_command.arguments();
150 if (m_macroExpander)
151 m_effectiveArguments = m_macroExpander->expand(m_effectiveArguments);
152 }
153 return m_effectiveArguments;
154 }
155
prettyCommand() const156 QString ProcessParameters::prettyCommand() const
157 {
158 QString cmd = m_command.executable().toString();
159 if (m_macroExpander)
160 cmd = m_macroExpander->expand(cmd);
161 return FilePath::fromString(cmd).fileName();
162 }
163
prettyArguments() const164 QString ProcessParameters::prettyArguments() const
165 {
166 QString margs = effectiveArguments();
167 QString workDir = effectiveWorkingDirectory().toString();
168 ProcessArgs::SplitError err;
169 ProcessArgs args =
170 ProcessArgs::prepareArgs(margs, &err, HostOsInfo::hostOs(), &m_environment, &workDir);
171 if (err != ProcessArgs::SplitOk)
172 return margs; // Sorry, too complex - just fall back.
173 return args.toString();
174 }
175
invalidCommandMessage(const QString & displayName)176 static QString invalidCommandMessage(const QString &displayName)
177 {
178 return QString("<b>%1:</b> <font color='%3'>%2</font>")
179 .arg(displayName,
180 QtcProcess::tr("Invalid command"),
181 creatorTheme()->color(Theme::TextColorError).name());
182 }
183
summary(const QString & displayName) const184 QString ProcessParameters::summary(const QString &displayName) const
185 {
186 if (m_commandMissing)
187 return invalidCommandMessage(displayName);
188
189 return QString::fromLatin1("<b>%1:</b> %2 %3")
190 .arg(displayName,
191 ProcessArgs::quoteArg(prettyCommand()),
192 prettyArguments());
193 }
194
summaryInWorkdir(const QString & displayName) const195 QString ProcessParameters::summaryInWorkdir(const QString &displayName) const
196 {
197 if (m_commandMissing)
198 return invalidCommandMessage(displayName);
199
200 return QString::fromLatin1("<b>%1:</b> %2 %3 in %4")
201 .arg(displayName,
202 ProcessArgs::quoteArg(prettyCommand()),
203 prettyArguments(),
204 QDir::toNativeSeparators(effectiveWorkingDirectory().toString()));
205 }
206
207 } // ProcessExplorer
208