Something went wrong. Try again.
The agentic engineering control plane for the posthuman future
Something went wrong. Try again.
8.5 kB · 202 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203#include "GitBridge.h"
#include <QDir>#include <QFileInfo>
GitBridge::GitBridge(QObject* parent) : QObject(parent) {}
QProcess* GitBridge::run(const QStringList& args, const QString& workingDirectory) { auto* process = new QProcess(); if (!workingDirectory.isEmpty()) { process->setWorkingDirectory(workingDirectory); } process->setProcessChannelMode(QProcess::SeparateChannels); process->setProgram(QStringLiteral("git")); process->setArguments(args);
// The process owns itself: after emitting finished it schedules a deferred // delete, which runs after every finished handler (including callers that // read stdout/stderr) has completed. A shared_ptr here would double-free: // deleteLater() deletes the raw object, then the shared_ptr refcount held // by the connection functor reaches zero and deletes it again. QObject::connect(process, &QProcess::finished, this, [this, process]() { m_busy = false; emit busyChanged(); process->deleteLater(); });
m_busy = true; emit busyChanged(); process->start(); return process;}
void GitBridge::repoRoot(const QString& path) { QString current = QDir::cleanPath(path); if (current.isEmpty()) { current = QDir::currentPath(); }
QString foundRoot; while (true) { const QString canonical = QFileInfo(current).canonicalFilePath(); if (canonical.isEmpty()) { break; } // Worktrees use a `.git` file pointing at the main repo's gitdir, while a // normal checkout has a `.git` directory; accept either. if (QFileInfo(canonical + QStringLiteral("/.git")).isDir() || QFileInfo(canonical + QStringLiteral("/.git")).isFile()) { foundRoot = canonical; break; } const QString parent = QFileInfo(canonical).absolutePath(); if (parent == canonical) { break; } current = parent; }
emit repoRootResolved(path, foundRoot);}
void GitBridge::listWorktrees(const QString& repoRoot) { const QStringList args = {QStringLiteral("-C"), repoRoot, QStringLiteral("worktree"), QStringLiteral("list"), QStringLiteral("--porcelain")}; QProcess* process = run(args, QString());
QObject::connect(process, &QProcess::finished, this, [this, process, repoRoot]() { const QByteArray output = process->readAllStandardOutput(); QVariantList items; const QStringList blocks = QString::fromUtf8(output).split(QStringLiteral("\n\n"), Qt::SkipEmptyParts); for (const QString& block : blocks) { QString path; QString name; for (const QString& line : block.split(QLatin1Char('\n'), Qt::SkipEmptyParts)) { if (line.startsWith(QStringLiteral("worktree "))) { path = line.mid(static_cast<int>(QStringLiteral("worktree ").size())); } else if (line.startsWith(QStringLiteral("branch "))) { const QString branch = line.mid(static_cast<int>(QStringLiteral("branch ").size())); if (branch.startsWith(QStringLiteral("refs/heads/"))) { name = branch.mid(static_cast<int>( QStringLiteral("refs/heads/").size())); } } else if (line == QStringLiteral("detached")) { name = QFileInfo(path).fileName(); } } if (path.isEmpty()) { continue; } // The current checkout is not a pickable worktree. if (QFileInfo(path).canonicalFilePath() == QFileInfo(repoRoot).canonicalFilePath()) { continue; } if (name.isEmpty()) { name = QFileInfo(path).fileName(); } QVariantMap item; item.insert(QStringLiteral("name"), name); item.insert(QStringLiteral("path"), path); items.append(item); } emit worktreesListed(items); });}
void GitBridge::addWorktree(const QString& repoRoot, const QString& path, const QString& name) { const QStringList args = {QStringLiteral("-C"), repoRoot, QStringLiteral("worktree"), QStringLiteral("add"), QStringLiteral("-b"), name, path}; QProcess* process = run(args, QString());
QObject::connect(process, &QProcess::finished, this, [this, process, path, name]() { const bool ok = process->exitStatus() == QProcess::NormalExit && process->exitCode() == 0; if (ok) { emit worktreeAdded(true, QString(), QFileInfo(path).canonicalFilePath(), name); } else { emit worktreeAdded( false, QString::fromUtf8(process->readAllStandardError()).trimmed(), QString(), name); } });}
void GitBridge::identify(const QString& path) { QString current = QDir::cleanPath(path); if (current.isEmpty()) { current = QDir::currentPath(); }
QProcess* process = run({QStringLiteral("-C"), current, QStringLiteral("rev-parse"), QStringLiteral("--show-toplevel")}, QString());
QObject::connect(process, &QProcess::finished, this, [this, process, path, current]() { const bool ok = process->exitStatus() == QProcess::NormalExit && process->exitCode() == 0; if (!ok) { emit identified(path, QString(), false); return; } const QString ownTop = QDir::cleanPath( QString::fromUtf8(process->readAllStandardOutput()) .trimmed());
// The common dir's toplevel is the main repository root. QProcess* common = run({QStringLiteral("-C"), current, QStringLiteral("rev-parse"), QStringLiteral("--git-common-dir")}, QString()); QObject::connect(common, &QProcess::finished, this, [this, common, path, current, ownTop]() { const bool ok = common->exitStatus() == QProcess::NormalExit && common->exitCode() == 0; if (!ok) { emit identified(path, QString(), false); return; } QString commonDir = QString::fromUtf8( common->readAllStandardOutput()) .trimmed(); if (QFileInfo(commonDir).isRelative()) { // git prints a relative path when the // command runs inside the repository. commonDir = QDir::cleanPath( QFileInfo(current, commonDir) .absoluteFilePath()); } const QFileInfo commonInfo(commonDir); QString repoRoot; if (commonInfo.isDir()) { // The common dir is the .git directory; // its parent is the main repository root. repoRoot = QDir::cleanPath(commonInfo.absolutePath()); } const bool isWorktree = !repoRoot.isEmpty() && QFileInfo(ownTop).canonicalFilePath() != QFileInfo(repoRoot).canonicalFilePath(); emit identified(path, repoRoot, isWorktree); }); });}