1 /*
2 SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "executeplugin.h"
8
9 #include <KConfigGroup>
10 #include <KJob>
11 #include <KLocalizedString>
12 #include <KParts/MainWindow>
13 #include <KPluginFactory>
14 #include <KShell>
15
16 #include <interfaces/icore.h>
17 #include <interfaces/iruncontroller.h>
18 #include <interfaces/ilaunchconfiguration.h>
19 #include <interfaces/iprojectcontroller.h>
20 #include <interfaces/iuicontroller.h>
21 #include <sublime/message.h>
22
23 #include "nativeappconfig.h"
24 #include "debug.h"
25 #include <project/projectmodel.h>
26 #include <project/builderjob.h>
27 #include <util/kdevstringhandler.h>
28
29 using namespace KDevelop;
30
31 K_PLUGIN_FACTORY_WITH_JSON(KDevExecuteFactory, "kdevexecute.json", registerPlugin<ExecutePlugin>();)
32
ExecutePlugin(QObject * parent,const QVariantList &)33 ExecutePlugin::ExecutePlugin(QObject *parent, const QVariantList&)
34 : KDevelop::IPlugin(QStringLiteral("kdevexecute"), parent)
35 {
36 m_configType = new NativeAppConfigType();
37 m_configType->addLauncher( new NativeAppLauncher() );
38 qCDebug(PLUGIN_EXECUTE) << "adding native app launch config";
39 core()->runController()->addConfigurationType( m_configType );
40 }
41
~ExecutePlugin()42 ExecutePlugin::~ExecutePlugin()
43 {
44 }
45
unload()46 void ExecutePlugin::unload()
47 {
48 core()->runController()->removeConfigurationType( m_configType );
49 delete m_configType;
50 m_configType = nullptr;
51 }
52
arguments(KDevelop::ILaunchConfiguration * cfg,QString & err_) const53 QStringList ExecutePlugin::arguments( KDevelop::ILaunchConfiguration* cfg, QString& err_ ) const
54 {
55
56 if( !cfg )
57 {
58 return QStringList();
59 }
60
61 KShell::Errors err;
62 QStringList args = KShell::splitArgs( cfg->config().readEntry( ExecutePlugin::argumentsEntry, "" ), KShell::TildeExpand | KShell::AbortOnMeta, &err );
63 if( err != KShell::NoError )
64 {
65
66 if( err == KShell::BadQuoting )
67 {
68 err_ = i18n("There is a quoting error in the arguments for "
69 "the launch configuration '%1'. Aborting start.", cfg->name() );
70 } else
71 {
72 err_ = i18n("A shell meta character was included in the "
73 "arguments for the launch configuration '%1', "
74 "this is not supported currently. Aborting start.", cfg->name() );
75 }
76 args = QStringList();
77 qCWarning(PLUGIN_EXECUTE) << "Launch Configuration:" << cfg->name() << "arguments have meta characters";
78 }
79 return args;
80 }
81
82
dependencyJob(KDevelop::ILaunchConfiguration * cfg) const83 KJob* ExecutePlugin::dependencyJob( KDevelop::ILaunchConfiguration* cfg ) const
84 {
85 const QVariantList deps = KDevelop::stringToQVariant( cfg->config().readEntry( dependencyEntry, QString() ) ).toList();
86 QString depAction = cfg->config().readEntry( dependencyActionEntry, "Nothing" );
87 if( depAction != QLatin1String("Nothing") && !deps.isEmpty() )
88 {
89 KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
90 QList<KDevelop::ProjectBaseItem*> items;
91 for (const QVariant& dep : deps) {
92 KDevelop::ProjectBaseItem* item = model->itemFromIndex( model->pathToIndex( dep.toStringList() ) );
93 if( item )
94 {
95 items << item;
96 }
97 else
98 {
99 const QString messageText = i18n("Couldn't resolve the dependency: %1", dep.toString());
100 auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
101 ICore::self()->uiController()->postMessage(message);
102 }
103 }
104 auto* job = new KDevelop::BuilderJob();
105 if( depAction == QLatin1String("Build") )
106 {
107 job->addItems( KDevelop::BuilderJob::Build, items );
108 } else if( depAction == QLatin1String("Install") )
109 {
110 job->addItems( KDevelop::BuilderJob::Install, items );
111 }
112 job->updateJobName();
113 return job;
114 }
115 return nullptr;
116 }
117
118
environmentProfileName(KDevelop::ILaunchConfiguration * cfg) const119 QString ExecutePlugin::environmentProfileName(KDevelop::ILaunchConfiguration* cfg) const
120 {
121 if( !cfg )
122 {
123 return QString();
124 }
125
126 return cfg->config().readEntry(ExecutePlugin::environmentProfileEntry, QString());
127 }
128
129
executable(KDevelop::ILaunchConfiguration * cfg,QString & err) const130 QUrl ExecutePlugin::executable( KDevelop::ILaunchConfiguration* cfg, QString& err ) const
131 {
132 QUrl executable;
133 if( !cfg )
134 {
135 return executable;
136 }
137 KConfigGroup grp = cfg->config();
138 if( grp.readEntry(ExecutePlugin::isExecutableEntry, false ) )
139 {
140 executable = grp.readEntry( ExecutePlugin::executableEntry, QUrl() );
141 } else
142 {
143 QStringList prjitem = grp.readEntry( ExecutePlugin::projectTargetEntry, QStringList() );
144 KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
145 KDevelop::ProjectBaseItem* item = model->itemFromIndex( model->pathToIndex(prjitem) );
146 if( item && item->executable() )
147 {
148 // TODO: Need an option in the gui to choose between installed and builddir url here, currently cmake only supports builddir url
149 executable = item->executable()->builtUrl();
150 }
151 }
152 if( executable.isEmpty() )
153 {
154 err = i18n("No valid executable specified");
155 qCWarning(PLUGIN_EXECUTE) << "Launch Configuration:" << cfg->name() << "no valid executable set";
156 } else
157 {
158 KShell::Errors err_;
159 if( KShell::splitArgs( executable.toLocalFile(), KShell::TildeExpand | KShell::AbortOnMeta, &err_ ).isEmpty() || err_ != KShell::NoError )
160 {
161 executable = QUrl();
162 if( err_ == KShell::BadQuoting )
163 {
164 err = i18n("There is a quoting error in the executable "
165 "for the launch configuration '%1'. "
166 "Aborting start.", cfg->name() );
167 } else
168 {
169 err = i18n("A shell meta character was included in the "
170 "executable for the launch configuration '%1', "
171 "this is not supported currently. Aborting start.", cfg->name() );
172 }
173 qCWarning(PLUGIN_EXECUTE) << "Launch Configuration:" << cfg->name() << "executable has meta characters";
174 }
175 }
176 return executable;
177 }
178
179
useTerminal(KDevelop::ILaunchConfiguration * cfg) const180 bool ExecutePlugin::useTerminal( KDevelop::ILaunchConfiguration* cfg ) const
181 {
182 if( !cfg )
183 {
184 return false;
185 }
186
187 return cfg->config().readEntry( ExecutePlugin::useTerminalEntry, false );
188 }
189
190
terminal(KDevelop::ILaunchConfiguration * cfg) const191 QString ExecutePlugin::terminal( KDevelop::ILaunchConfiguration* cfg ) const
192 {
193 if( !cfg )
194 {
195 return QString();
196 }
197
198 return cfg->config().readEntry( ExecutePlugin::terminalEntry, QString() );
199 }
200
201
workingDirectory(KDevelop::ILaunchConfiguration * cfg) const202 QUrl ExecutePlugin::workingDirectory( KDevelop::ILaunchConfiguration* cfg ) const
203 {
204 if( !cfg )
205 {
206 return QUrl();
207 }
208
209 return cfg->config().readEntry( ExecutePlugin::workingDirEntry, QUrl() );
210 }
211
212
nativeAppConfigTypeId() const213 QString ExecutePlugin::nativeAppConfigTypeId() const
214 {
215 return NativeAppConfigType::sharedId();
216 }
217
218
219 #include "executeplugin.moc"
220