1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "pythondebugger.h" |
6 | |
7 | #include <QProcess> |
8 | #include <QDebug> |
9 | #include <QDBusConnection> |
10 | #include <QDBusMessage> |
11 | #include <QApplication> |
12 | #include <QDir> |
13 | |
14 | class PythonDebuggerPrivate { |
15 | friend class PythonDebugger; |
16 | QProcess process; |
17 | int port = 0; |
18 | }; |
19 | |
20 | PythonDebugger::PythonDebugger(QObject *parent) |
21 | : QObject(parent) |
22 | , d(new PythonDebuggerPrivate()) |
23 | { |
24 | registerLaunchDAPConnect(); |
25 | |
26 | connect(this, &PythonDebugger::sigSendToClient, [](const QString &uuid, int port, const QString &kit, |
27 | const QString &projectPath) { |
28 | QDBusMessage msg = QDBusMessage::createSignal("/path" , |
29 | "com.deepin.unioncode.interface" , |
30 | "dapport" ); |
31 | QMap<QString, QVariant> param; |
32 | param.insert("workspace" , projectPath); |
33 | msg << uuid |
34 | << port |
35 | << kit |
36 | << param; |
37 | QDBusConnection::sessionBus().send(msg); |
38 | }); |
39 | |
40 | connect(&d->process, &QProcess::readyReadStandardOutput, [this]() { |
41 | QByteArray data = d->process.readAllStandardOutput(); |
42 | //qInfo() << "message:" << qPrintable(data); |
43 | }); |
44 | |
45 | connect(&d->process, &QProcess::readyReadStandardError, [this]() { |
46 | QByteArray data = d->process.readAllStandardError(); |
47 | //qInfo() << "error:" << qPrintable(data); |
48 | }); |
49 | } |
50 | |
51 | PythonDebugger::~PythonDebugger() |
52 | { |
53 | if (d) |
54 | delete d; |
55 | } |
56 | |
57 | void PythonDebugger::registerLaunchDAPConnect() |
58 | { |
59 | QDBusConnection sessionBus = QDBusConnection::sessionBus(); |
60 | sessionBus.disconnect(QString("" ), |
61 | "/path" , |
62 | "com.deepin.unioncode.interface" , |
63 | "launch_python_dap" , |
64 | this, SLOT(slotReceiveClientInfo(QString, QString, QString, QString, QString, QString))); |
65 | sessionBus.connect(QString("" ), |
66 | "/path" , |
67 | "com.deepin.unioncode.interface" , |
68 | "launch_python_dap" , |
69 | this, SLOT(slotReceiveClientInfo(QString, QString, QString, QString, QString, QString))); |
70 | } |
71 | |
72 | void PythonDebugger::initialize(const QString &pythonExecute, |
73 | const QString &fileName, |
74 | const QString &projectCachePath) |
75 | { |
76 | int startPort = 7000; |
77 | auto checkPortFree = [](int port) { |
78 | QProcess process; |
79 | QString cmd = QString("fuser %1/tcp" ).arg(port); |
80 | process.start(cmd); |
81 | process.waitForFinished(); |
82 | QString ret = process.readAll(); |
83 | if (ret.isEmpty()) |
84 | return true; |
85 | return false; |
86 | }; |
87 | |
88 | while (startPort) { |
89 | if (checkPortFree(startPort)) { |
90 | break; |
91 | } |
92 | startPort--; |
93 | } |
94 | |
95 | d->port = startPort; |
96 | QString validPort = QString::number(d->port); |
97 | QString pid = QString::number(QApplication::applicationPid()); |
98 | QString logFolder = projectCachePath + "/dap/pylog" ; |
99 | QString param = pythonExecute + " -m debugpy --listen " + validPort + |
100 | " --wait-for-client --log-to " + logFolder + " " + fileName + " --pid " + pid; |
101 | qInfo() << param; |
102 | |
103 | QStringList options; |
104 | options << "-c" << param; |
105 | d->process.start("/bin/bash" , options); |
106 | d->process.waitForStarted(); |
107 | } |
108 | |
109 | void PythonDebugger::slotReceiveClientInfo(const QString &uuid, |
110 | const QString &kit, |
111 | const QString &pythonExecute, |
112 | const QString &fileName, |
113 | const QString &projectPath, |
114 | const QString &projectCachePath) |
115 | { |
116 | d->port = 0; |
117 | d->process.close(); |
118 | initialize(pythonExecute, fileName, projectCachePath); |
119 | emit sigSendToClient(uuid, d->port, kit, projectPath); |
120 | } |
121 | |
122 | |
123 | |