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
14class PythonDebuggerPrivate {
15 friend class PythonDebugger;
16 QProcess process;
17 int port = 0;
18};
19
20PythonDebugger::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
51PythonDebugger::~PythonDebugger()
52{
53 if (d)
54 delete d;
55}
56
57void 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
72void 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
109void 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