1 /**************************************************************************
2 ** This file is part of LiteIDE
3 **
4 ** Copyright (c) 2011-2019 LiteIDE. All rights reserved.
5 **
6 ** This library is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU Lesser General Public
8 ** License as published by the Free Software Foundation; either
9 ** version 2.1 of the License, or (at your option) any later version.
10 **
11 ** This library is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** Lesser General Public License for more details.
15 **
16 ** In addition, as a special exception, that plugins developed for LiteIDE,
17 ** are allowed to remain closed sourced and can be distributed under any license .
18 ** These rights are included in the file LGPL_EXCEPTION.txt in this package.
19 **
20 **************************************************************************/
21 // Module: liteenvapi.h
22 // Creator: visualfc <visualfc@gmail.com>
23
24 #ifndef LITEENVAPI_H
25 #define LITEENVAPI_H
26
27 #include "liteapi/liteapi.h"
28 #include <QProcessEnvironment>
29 #include <QDir>
30 #include <QDebug>
31
32 namespace LiteApi {
33
34 class IEnv : public QObject
35 {
36 Q_OBJECT
37 public:
QObject(parent)38 IEnv(QObject *parent = 0): QObject(parent) {}
~IEnv()39 virtual ~IEnv() {}
40 virtual QString id() const = 0;
41 virtual QString filePath() const = 0;
42 virtual QStringList orgEnvLines() const = 0;
43 virtual QMap<QString,QString> goEnvMap() const = 0;
44 virtual QProcessEnvironment& environment() = 0;
45 virtual void reload() = 0;
46 signals:
47 void goenvError(QString,QString);
48 void goenvChanged(QString);
49 };
50
51 class IEnvManager : public IManager
52 {
53 Q_OBJECT
54 public:
IManager(parent)55 IEnvManager(QObject *parent = 0) : IManager(parent) {}
56 virtual QList<IEnv*> envList() const = 0;
57 virtual IEnv *findEnv(const QString &id, const QString &backup = "system") const = 0;
58 virtual void setCurrentEnvId(const QString &id) = 0;
59 virtual IEnv *currentEnv() const = 0;
60 virtual QProcessEnvironment currentEnvironment() const = 0;
61 virtual void reloadCurrentEnv() = 0;
62 signals:
63 void currentEnvChanged(LiteApi::IEnv*);
64 };
65
66 class IGoEnvManger: public IManager
67 {
68 Q_OBJECT
69 public:
IManager(parent)70 IGoEnvManger(QObject *parent = 0) : IManager(parent) {}
71 virtual QString gocmd() const = 0;
72 virtual QString gotools() const = 0;
73 virtual QString GOROOT() const = 0;
74 virtual QStringList GOPATH() const = 0;
75 virtual QProcessEnvironment environment() const = 0;
76 virtual QProcessEnvironment customEnvironment(const QString &buildFilePath, QString *pCustomBuildPath = 0) const = 0;
77 virtual QStringList customGOPATH(const QString &buildPath, QString *pCustomBuildPath = 0) const = 0;
78 virtual QString findRealCustomBuildPath(const QString &buildPath) const = 0;
79 virtual bool hasCustomGOPATH(const QString &buildPath) const = 0;
80 virtual void updateGoEnv() = 0;
81 virtual void updateCustomGOPATH(const QString &buildPath) = 0;
82 signals:
83 void globalGOPATHChanged();
84 void customGOPATHChanged(const QString &buildPath);
85 };
86
getEnvManager(LiteApi::IApplication * app)87 inline IEnvManager *getEnvManager(LiteApi::IApplication* app)
88 {
89 return LiteApi::findExtensionObject<IEnvManager*>(app,"LiteApi.IEnvManager");
90 }
91
getGoEnvManager(LiteApi::IApplication * app)92 inline IGoEnvManger *getGoEnvManager(LiteApi::IApplication *app)
93 {
94 return LiteApi::findExtensionObject<IGoEnvManger*>(app,"LiteApi.IGoEnvManger");
95 }
96
getCurrentEnvironment(LiteApi::IApplication * app)97 inline QProcessEnvironment getCurrentEnvironment(LiteApi::IApplication *app)
98 {
99 QProcessEnvironment e;
100 IEnvManager *env = getEnvManager(app);
101 if (env) {
102 e = env->currentEnvironment();
103 } else {
104 e = QProcessEnvironment::systemEnvironment();
105 }
106 #ifdef Q_OS_WIN
107 QString sep = ";";
108 #else
109 QString sep = ":";
110 #endif
111 QStringList pathList;
112 foreach (QString path, e.value("PATH").split(sep,QString::SkipEmptyParts)) {
113 pathList.append(QDir::toNativeSeparators(path));
114 }
115 pathList.append(app->applicationPath());
116 pathList.removeDuplicates();
117 e.insert("PATH",pathList.join(sep));
118 return e;
119 }
120
getDefaultGOOS()121 inline QString getDefaultGOOS()
122 {
123 const char* goos = "";
124 #ifdef Q_OS_WIN
125 goos = "windows";
126 #endif
127 #ifdef Q_OS_LINUX
128 goos = "linux";
129 #endif
130 #ifdef Q_OS_DARWIN
131 goos = "darwin";
132 #endif
133 #ifdef Q_OS_FREEBSD
134 goos = "freebsd";
135 #endif
136 #ifdef Q_OS_OPENBSD
137 goos = "openbsd";
138 #endif
139 return goos;
140 }
141
getDefaultGOROOT()142 inline QString getDefaultGOROOT()
143 {
144 #ifdef Q_OS_WIN
145 return "c:\\go";
146 #else
147 return "/usr/local/go";
148 #endif
149 }
150
hasGoEnv(const QProcessEnvironment & env)151 inline bool hasGoEnv(const QProcessEnvironment &env)
152 {
153 return env.contains("GOROOT") && env.contains("GOARCH");
154 }
155
getSysEnvironment(LiteApi::IApplication * app)156 inline QProcessEnvironment getSysEnvironment(LiteApi::IApplication *app)
157 {
158 QProcessEnvironment env = getCurrentEnvironment(app);
159 #ifdef Q_OS_WIN
160 QString sep = ";";
161 #else
162 QString sep = ":";
163 #endif
164
165 IEnvManager *mgr = LiteApi::getEnvManager(app);
166 if (mgr) {
167 LiteApi::IEnv *ce = mgr->currentEnv();
168 if (ce) {
169 QMapIterator<QString,QString> i(ce->goEnvMap());
170 while(i.hasNext()) {
171 i.next();
172 env.insert(i.key(),i.value());
173 }
174 }
175 }
176
177 QString goos = env.value("GOOS");
178 if (goos.isEmpty()) {
179 goos = getDefaultGOOS();
180 }
181
182 QString goroot = env.value("GOROOT");
183 if (goroot.isEmpty()) {
184 goroot = getDefaultGOROOT();
185 }
186 return env;
187 }
188
189
getGoEnvironment(LiteApi::IApplication * app)190 inline QProcessEnvironment getGoEnvironment(LiteApi::IApplication *app)
191 {
192 QProcessEnvironment env = getCurrentEnvironment(app);
193 #ifdef Q_OS_WIN
194 QString sep = ";";
195 #else
196 QString sep = ":";
197 #endif
198
199 IEnvManager *mgr = LiteApi::getEnvManager(app);
200 if (mgr) {
201 LiteApi::IEnv *ce = mgr->currentEnv();
202 if (ce) {
203 QMapIterator<QString,QString> i(ce->goEnvMap());
204 while(i.hasNext()) {
205 i.next();
206 env.insert(i.key(),i.value());
207 }
208 }
209 }
210
211 QString goos = env.value("GOOS");
212 if (goos.isEmpty()) {
213 goos = getDefaultGOOS();
214 }
215 if (!env.contains("GOEXE")) {
216 QString goexe;
217 if (goos == "windows") {
218 goexe = ".exe";
219 }
220 env.insert("GOEXE",goexe);
221 }
222
223 QString goarch = env.value("GOARCH");
224 QString goroot = env.value("GOROOT");
225 if (goroot.isEmpty()) {
226 goroot = getDefaultGOROOT();
227 }
228
229 if (app->settings()->value("liteide/use111gomodule",false).toBool()) {
230 env.insert("GO111MODULE",app->settings()->value("liteide/go111module").toString());
231 }
232 if (app->settings()->value("liteide/usegoproxy",false).toBool()) {
233 env.insert("GOPROXY",app->settings()->value("liteide/goproxy").toString());
234 }
235 if (app->settings()->value("liteide/usegoprivate",false).toBool()) {
236 env.insert("GOPRIVATE",app->settings()->value("liteide/goprivate").toString());
237 }
238 if (app->settings()->value("liteide/usegonoproxy",false).toBool()) {
239 env.insert("GONOPROXY",app->settings()->value("liteide/gonoproxy").toString());
240 }
241 if (app->settings()->value("liteide/usegonosumdb",false).toBool()) {
242 env.insert("GONOSUMDB",app->settings()->value("liteide/gonosumdb").toString());
243 }
244
245 QStringList pathList;
246 if (app->settings()->value("liteide/usesysgopath",true).toBool()) {
247 foreach (QString path, env.value("GOPATH").split(sep,QString::SkipEmptyParts)) {
248 pathList.append(QDir::toNativeSeparators(path));
249 }
250 }
251 if (app->settings()->value("liteide/uselitegopath",true).toBool()) {
252 foreach (QString path, app->settings()->value("liteide/gopath").toStringList()) {
253 pathList.append(QDir::toNativeSeparators(path));
254 }
255 }
256 pathList.removeDuplicates();
257 env.insert("GOPATH",pathList.join(sep));
258
259 if (!goroot.isEmpty()) {
260 pathList.prepend(goroot);
261 }
262
263 QStringList binList;
264 QString gobin = env.value("GOBIN");
265 if (!gobin.isEmpty()) {
266 binList.append(gobin);
267 }
268 foreach (QString path, pathList) {
269 binList.append(QFileInfo(path,"bin").filePath());
270 binList.append(QFileInfo(path,"bin/"+goos+"_"+goarch).filePath());
271 }
272 env.insert("PATH",env.value("PATH")+sep+binList.join(sep)+sep);
273
274 return env;
275 }
276
getGOPATH(LiteApi::IApplication * app,bool includeGoroot)277 inline QStringList getGOPATH(LiteApi::IApplication *app, bool includeGoroot)
278 {
279 QProcessEnvironment env = getGoEnvironment(app);
280 #ifdef Q_OS_WIN
281 QString sep = ";";
282 #else
283 QString sep = ":";
284 #endif
285 QStringList pathList;
286 QString goroot = QDir::toNativeSeparators(env.value("GOROOT"));
287 if (includeGoroot) {
288 pathList.append(goroot);
289 }
290 foreach (QString path, env.value("GOPATH").split(sep,QString::SkipEmptyParts)) {
291 pathList.append(QDir::toNativeSeparators(path));
292 }
293 if (!includeGoroot) {
294 pathList.removeAll(goroot);
295 }
296 pathList.removeDuplicates();
297 return pathList;
298 }
299
getGOROOT(LiteApi::IApplication * app)300 inline QString getGOROOT(LiteApi::IApplication *app)
301 {
302 return getGoEnvironment(app).value("GOROOT");
303 }
304
lookupSrcRoot(const QString & buildFilePath)305 inline QString lookupSrcRoot(const QString &buildFilePath)
306 {
307 int index = buildFilePath.indexOf("/src/");
308 if (index < 0) {
309 return QString();
310 }
311 return buildFilePath.left(index+4);
312 }
313
314 inline QString lookupParentHasCustom(LiteApi::IApplication *app, const QString &buildFilePath, const QString &srcRoot, QString *pCustomParent = 0)
315 {
316 QFileInfo info(buildFilePath);
317 QString parent = info.path();
318
319 if (parent == srcRoot || info.dir().isRoot()) {
320 return QString();
321 }
322 QString customKey = "litebuild-custom/"+parent;
323 bool use_custom_gopath = app->settings()->value(customKey+"#use_custom_gopath",false).toBool();
324 if (use_custom_gopath) {
325 if (pCustomParent) {
326 *pCustomParent = parent;
327 }
328 return customKey;
329 }
330 return lookupParentHasCustom(app,parent,srcRoot);
331 }
332
333 inline QProcessEnvironment getCustomGoEnvironment(LiteApi::IApplication *app, const QString &buildFilePath, QString *pCustomBuildPath = 0)
334 {
335 if (buildFilePath.isEmpty()) {
336 return getGoEnvironment(app);
337 }
338 QString customKey = "litebuild-custom/"+buildFilePath;
339 QString customBuildPath = buildFilePath;
340 bool use_custom_gopath = app->settings()->value(customKey+"#use_custom_gopath",false).toBool();
341 if (!use_custom_gopath) {
342 QString srcRoot = lookupSrcRoot(buildFilePath);
343 if (!srcRoot.isEmpty()) {
344 customKey = lookupParentHasCustom(app,buildFilePath,srcRoot, &customBuildPath);
345 if (!customKey.isEmpty()) {
346 use_custom_gopath = true;
347 }
348 }
349 }
350 if (!use_custom_gopath) {
351 return getGoEnvironment(app);
352 }
353 if (pCustomBuildPath) {
354 *pCustomBuildPath = customBuildPath;
355 }
356
357 QProcessEnvironment env = getCurrentEnvironment(app);
358 #ifdef Q_OS_WIN
359 QString sep = ";";
360 #else
361 QString sep = ":";
362 #endif
363
364 IEnvManager *mgr = LiteApi::getEnvManager(app);
365 if (mgr) {
366 LiteApi::IEnv *ce = mgr->currentEnv();
367 if (ce) {
368 QMapIterator<QString,QString> i(ce->goEnvMap());
369 while(i.hasNext()) {
370 i.next();
371 env.insert(i.key(),i.value());
372 }
373 }
374 }
375
376 QString goos = env.value("GOOS");
377 if (goos.isEmpty()) {
378 goos = getDefaultGOOS();
379 }
380 if (!env.contains("GOEXE")) {
381 QString goexe;
382 if (goos == "windows") {
383 goexe = ".exe";
384 }
385 env.insert("GOEXE",goexe);
386 }
387
388 QString goarch = env.value("GOARCH");
389 QString goroot = env.value("GOROOT");
390 if (goroot.isEmpty()) {
391 goroot = getDefaultGOROOT();
392 }
393
394 QStringList pathList;
395
396 bool inherit_sys_gopath = app->settings()->value(customKey+"#inherit_sys_gopath",true).toBool();
397 bool inherit_lite_gopath = app->settings()->value(customKey+"#inherit_lite_gopath",true).toBool();
398 bool custom_gopath = app->settings()->value(customKey+"#custom_gopath",false).toBool();
399
400 if (inherit_sys_gopath) {
401 foreach (QString path, env.value("GOPATH").split(sep,QString::SkipEmptyParts)) {
402 pathList.append(QDir::toNativeSeparators(path));
403 }
404 }
405 if (inherit_lite_gopath) {
406 foreach (QString path, app->settings()->value("liteide/gopath").toStringList()) {
407 pathList.append(QDir::toNativeSeparators(path));
408 }
409 }
410 if (custom_gopath) {
411 foreach (QString path, app->settings()->value(customKey+"#gopath").toStringList()) {
412 pathList.append(QDir::toNativeSeparators(path));
413 }
414 }
415 pathList.removeDuplicates();
416 env.insert("GOPATH",pathList.join(sep));
417
418 if (!goroot.isEmpty()) {
419 pathList.prepend(goroot);
420 }
421
422 QStringList binList;
423 QString gobin = env.value("GOBIN");
424 if (!gobin.isEmpty()) {
425 binList.append(gobin);
426 }
foreach(QString path,pathList)427 foreach (QString path, pathList) {
428 binList.append(QFileInfo(path,"bin").filePath());
429 binList.append(QFileInfo(path,"bin/"+goos+"_"+goarch).filePath());
430 }
431 env.insert("PATH",env.value("PATH")+sep+binList.join(sep)+sep);
432 return env;
433 }
434
getCustomGoEnvironment(LiteApi::IApplication * app,LiteApi::IEditor * editor)435 inline QProcessEnvironment getCustomGoEnvironment(LiteApi::IApplication *app, LiteApi::IEditor *editor)
436 {
437 QString buildFilePath;
438 if (editor) {
439 QString filePath = editor->filePath();
440 if (!filePath.isEmpty()) {
441 buildFilePath = QFileInfo(filePath).path();
442 }
443 }
444 return getCustomGoEnvironment(app,buildFilePath);
445 }
446
447 } //namespace LiteApi
448
449
450 #endif //LITEENVAPI_H
451
452