1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "processutil.h" |
6 | |
7 | #include <QProcess> |
8 | #include <QFileInfo> |
9 | #include <QDirIterator> |
10 | #include <QDebug> |
11 | #include <QUrl> |
12 | |
13 | bool ProcessUtil::execute(const QString &program, |
14 | const QStringList &arguments, |
15 | ProcessUtil::ReadCallBack func) |
16 | { |
17 | return ProcessUtil::execute(program, arguments, "" , func); |
18 | } |
19 | |
20 | bool ProcessUtil::execute(const QString &program, |
21 | const QStringList &arguments, |
22 | const QString &workdir, |
23 | ProcessUtil::ReadCallBack func) |
24 | { |
25 | return execute(program, arguments, workdir, QProcess().processEnvironment(), func); |
26 | } |
27 | |
28 | bool ProcessUtil::execute(const QString &program, |
29 | const QStringList &arguments, |
30 | const QString &workdir, |
31 | const QProcessEnvironment &env, |
32 | ProcessUtil::ReadCallBack func) |
33 | { |
34 | bool ret = true; |
35 | QProcess process; |
36 | process.setWorkingDirectory(workdir); |
37 | process.setProgram(program); |
38 | process.setArguments(arguments); |
39 | process.setProcessEnvironment(env); |
40 | process.connect(&process, QOverload<int, QProcess::ExitStatus >::of(&QProcess::finished), |
41 | [&](int exitCode, QProcess::ExitStatus exitStatus){ |
42 | if (exitCode != 0) |
43 | ret = false; |
44 | qInfo() << program << arguments.join(" " ) |
45 | << "exitCode: " << exitCode |
46 | << "exitStatus: " << exitStatus; |
47 | }); |
48 | process.connect(&process, &QProcess::errorOccurred, |
49 | [&](QProcess::ProcessError error){ |
50 | ret = false; |
51 | qCritical() << program << arguments.join(" " ) |
52 | << "error: " << error |
53 | << "errorString: " << process.errorString(); |
54 | }); |
55 | |
56 | process.start(); |
57 | process.waitForFinished(); |
58 | |
59 | if (func) { |
60 | QByteArray array = process.readAll(); |
61 | func(array.trimmed()); |
62 | } |
63 | |
64 | return ret; |
65 | } |
66 | |
67 | QString ProcessUtil::execute(const QStringList &commands, bool cascade) |
68 | { |
69 | auto executeCascade = [&](QString command, QString arg)->QString{ |
70 | QString ret; |
71 | execute("bash" , QStringList() << "-c" << (command + " " + arg), [&](const QByteArray &output){ |
72 | ret = output; |
73 | }); |
74 | return ret; |
75 | }; |
76 | |
77 | QString ret; |
78 | foreach (QString command, commands) { |
79 | if (cascade) { |
80 | ret = executeCascade(command, ret); |
81 | } else{ |
82 | executeCascade(command, {}); |
83 | } |
84 | } |
85 | return ret; |
86 | } |
87 | |
88 | bool ProcessUtil::exists(const QString &name) |
89 | { |
90 | bool ret = false; |
91 | #ifdef linux |
92 | auto outCallback = [&ret, &name](const QByteArray &array) { |
93 | QList<QByteArray> rmSearch = array.split(' '); |
94 | foreach (QByteArray rmProcess, rmSearch) { |
95 | QFileInfo info(rmProcess.trimmed()); |
96 | if (info.exists() && info.fileName() == name && info.isExecutable()) { |
97 | if (!ret) { |
98 | ret = true; |
99 | break; |
100 | } |
101 | } else { |
102 | ret = false; |
103 | } |
104 | } |
105 | }; |
106 | ProcessUtil::execute("whereis" , {name}, outCallback); |
107 | #else |
108 | #endif |
109 | return ret; |
110 | } |
111 | |
112 | QString ProcessUtil::version(const QString &name) |
113 | { |
114 | QString retOut; |
115 | #ifdef linux |
116 | auto outCallback = [&retOut](const QByteArray &array) { |
117 | retOut = QString ::fromLatin1(array); |
118 | }; |
119 | ProcessUtil::execute(name, {"-version" }, outCallback); |
120 | #else |
121 | #endif |
122 | return retOut; |
123 | } |
124 | |
125 | bool ProcessUtil::hasGio() |
126 | { |
127 | return exists("gio" ); |
128 | } |
129 | |
130 | bool ProcessUtil::moveToTrash(const QString &filePath) |
131 | { |
132 | #ifdef linux |
133 | if (!hasGio()) |
134 | return false; |
135 | return ProcessUtil::execute("gio" , {"trash" , filePath}); |
136 | #else |
137 | |
138 | #endif |
139 | } |
140 | |
141 | bool ProcessUtil::recoverFromTrash(const QString &filePath) |
142 | { |
143 | #ifdef linux |
144 | if (!hasGio() || filePath.isEmpty()) |
145 | return false; |
146 | |
147 | QDirIterator itera(QDir::homePath() + QDir::separator() + ".local/share/Trash/files" ); |
148 | while (itera.hasNext()){ |
149 | itera.next(); |
150 | QFileInfo info(filePath); |
151 | if(info.suffix() == itera.fileInfo().suffix() |
152 | && info.baseName() == itera.fileInfo().baseName()) { |
153 | QByteArray readArray; |
154 | auto readCB = [&](const QByteArray array){readArray = array;}; |
155 | QString trashFileUri = QString("trash:///%0" ).arg(info.fileName()); |
156 | QStringList queryArgs; |
157 | queryArgs << "info" ; |
158 | queryArgs << trashFileUri; |
159 | queryArgs << "| grep trash::orig-path" ; |
160 | bool execResult = ProcessUtil::execute("gio" , queryArgs, readCB); |
161 | if (!execResult && readArray.isEmpty()) { |
162 | qCritical() << "Unknown Error" ; |
163 | abort(); |
164 | } |
165 | readArray = readArray.replace(" " , "" ); |
166 | auto list = readArray.split('\n'); |
167 | auto itera = list.rbegin(); |
168 | while (itera != list.rend()) { |
169 | if (itera->startsWith("trash::orig-path:" )) { |
170 | readArray = *itera; |
171 | break; |
172 | } |
173 | itera ++; |
174 | } |
175 | if (!readArray.startsWith("trash::orig-path:" )) { |
176 | qCritical() << "Error from: " <<QString::fromUtf8(readArray); |
177 | abort(); |
178 | } |
179 | readArray = readArray.replace("trash::orig-path:" , "" ); |
180 | if (readArray == filePath) { |
181 | QStringList args; |
182 | args << "move" ; |
183 | args << trashFileUri; |
184 | args << QUrl::fromLocalFile(filePath).toString(); |
185 | return ProcessUtil::execute("gio" , args); |
186 | } |
187 | } |
188 | } |
189 | |
190 | #else |
191 | |
192 | #endif |
193 | return false; |
194 | } |
195 | |
196 | bool ProcessUtil::portOverhead(unsigned int port) |
197 | { |
198 | bool ret = true; |
199 | #ifdef linux |
200 | auto outCallback = [&ret](const QByteArray &array) { |
201 | qInfo() << qPrintable(array); |
202 | if (array.isEmpty()) { |
203 | ret = false; |
204 | } |
205 | }; |
206 | ProcessUtil::execute("/bin/bash" , {"-c" , "ss -ntlp|grep " + QString::number(port)}, outCallback); |
207 | #else |
208 | #endif |
209 | return ret; |
210 | } |
211 | |
212 | QString ProcessUtil::localPlatform() |
213 | { |
214 | // get location platform |
215 | QString platform = "" ; |
216 | bool platfromQueRes = ProcessUtil::execute("arch" , {}, [&](const QByteArray &data){ |
217 | platform = QString(data).replace("\n" ,"" ); |
218 | }); |
219 | if (!platfromQueRes) |
220 | qCritical() << "usr command arch failed, please check tool program arch" ; |
221 | else if (platform.isEmpty()) |
222 | qCritical() << "query local platform failed, not support \"arch\" command?" ; |
223 | return platform; |
224 | } |
225 | |
226 | |