forked from quickshell/quickshell
		
	core/command: improve dead instance selection
Prints dead instances if they exist, as well as allowing dead instance selection for a substring if no live instances exist.
This commit is contained in:
		
							parent
							
								
									86591f122d
								
							
						
					
					
						commit
						0e6518a706
					
				
					 8 changed files with 86 additions and 24 deletions
				
			
		| 
						 | 
					@ -3,12 +3,12 @@
 | 
				
			||||||
#include <qdatastream.h>
 | 
					#include <qdatastream.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QDataStream& operator<<(QDataStream& stream, const InstanceInfo& info) {
 | 
					QDataStream& operator<<(QDataStream& stream, const InstanceInfo& info) {
 | 
				
			||||||
	stream << info.instanceId << info.configPath << info.shellId << info.launchTime;
 | 
						stream << info.instanceId << info.configPath << info.shellId << info.launchTime << info.pid;
 | 
				
			||||||
	return stream;
 | 
						return stream;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QDataStream& operator>>(QDataStream& stream, InstanceInfo& info) {
 | 
					QDataStream& operator>>(QDataStream& stream, InstanceInfo& info) {
 | 
				
			||||||
	stream >> info.instanceId >> info.configPath >> info.shellId >> info.launchTime;
 | 
						stream >> info.instanceId >> info.configPath >> info.shellId >> info.launchTime >> info.pid;
 | 
				
			||||||
	return stream;
 | 
						return stream;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,12 +3,14 @@
 | 
				
			||||||
#include <qdatetime.h>
 | 
					#include <qdatetime.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
#include <qstring.h>
 | 
					#include <qstring.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct InstanceInfo {
 | 
					struct InstanceInfo {
 | 
				
			||||||
	QString instanceId;
 | 
						QString instanceId;
 | 
				
			||||||
	QString configPath;
 | 
						QString configPath;
 | 
				
			||||||
	QString shellId;
 | 
						QString shellId;
 | 
				
			||||||
	QDateTime launchTime;
 | 
						QDateTime launchTime;
 | 
				
			||||||
 | 
						pid_t pid = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static InstanceInfo CURRENT; // NOLINT
 | 
						static InstanceInfo CURRENT; // NOLINT
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include <qdir.h>
 | 
					#include <qdir.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
#include <qloggingcategory.h>
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
 | 
					#include <qpair.h>
 | 
				
			||||||
#include <qstandardpaths.h>
 | 
					#include <qstandardpaths.h>
 | 
				
			||||||
#include <qtenvironmentvariables.h>
 | 
					#include <qtenvironmentvariables.h>
 | 
				
			||||||
#include <qtversionchecks.h>
 | 
					#include <qtversionchecks.h>
 | 
				
			||||||
| 
						 | 
					@ -367,29 +368,30 @@ bool QsPaths::checkLock(const QString& path, InstanceLockInfo* info, bool allowD
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QVector<InstanceLockInfo> QsPaths::collectInstances(const QString& path, bool fallbackDead) {
 | 
					QPair<QVector<InstanceLockInfo>, QVector<InstanceLockInfo>>
 | 
				
			||||||
 | 
					QsPaths::collectInstances(const QString& path) {
 | 
				
			||||||
	qCDebug(logPaths) << "Collecting instances from" << path;
 | 
						qCDebug(logPaths) << "Collecting instances from" << path;
 | 
				
			||||||
	auto instances = QVector<InstanceLockInfo>();
 | 
						auto liveInstances = QVector<InstanceLockInfo>();
 | 
				
			||||||
 | 
						auto deadInstances = QVector<InstanceLockInfo>();
 | 
				
			||||||
	auto dir = QDir(path);
 | 
						auto dir = QDir(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	InstanceLockInfo info;
 | 
						InstanceLockInfo info;
 | 
				
			||||||
	for (auto& entry: dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
 | 
						for (auto& entry: dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
 | 
				
			||||||
		auto path = dir.filePath(entry);
 | 
							auto path = dir.filePath(entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (QsPaths::checkLock(path, &info, fallbackDead)) {
 | 
							if (QsPaths::checkLock(path, &info, true)) {
 | 
				
			||||||
			if (fallbackDead && info.pid != -1) {
 | 
					 | 
				
			||||||
				fallbackDead = false;
 | 
					 | 
				
			||||||
				instances.clear();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			qCDebug(logPaths).nospace() << "Found instance " << info.instance.instanceId << " (pid "
 | 
								qCDebug(logPaths).nospace() << "Found instance " << info.instance.instanceId << " (pid "
 | 
				
			||||||
			                            << info.pid << ") at " << path;
 | 
								                            << info.pid << ") at " << path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			instances.push_back(info);
 | 
								if (info.pid == -1) {
 | 
				
			||||||
 | 
									deadInstances.push_back(info);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									liveInstances.push_back(info);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			qCDebug(logPaths) << "Skipped potential instance at" << path;
 | 
								qCDebug(logPaths) << "Skipped potential instance at" << path;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return instances;
 | 
						return qMakePair(liveInstances, deadInstances);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <qdatetime.h>
 | 
					#include <qdatetime.h>
 | 
				
			||||||
#include <qdir.h>
 | 
					#include <qdir.h>
 | 
				
			||||||
 | 
					#include <qpair.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "instanceinfo.hpp"
 | 
					#include "instanceinfo.hpp"
 | 
				
			||||||
| 
						 | 
					@ -22,7 +23,8 @@ public:
 | 
				
			||||||
	static QString ipcPath(const QString& id);
 | 
						static QString ipcPath(const QString& id);
 | 
				
			||||||
	static bool
 | 
						static bool
 | 
				
			||||||
	checkLock(const QString& path, InstanceLockInfo* info = nullptr, bool allowDead = false);
 | 
						checkLock(const QString& path, InstanceLockInfo* info = nullptr, bool allowDead = false);
 | 
				
			||||||
	static QVector<InstanceLockInfo> collectInstances(const QString& path, bool fallbackDead = false);
 | 
						static QPair<QVector<InstanceLockInfo>, QVector<InstanceLockInfo>>
 | 
				
			||||||
 | 
						collectInstances(const QString& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QDir* baseRunDir();
 | 
						QDir* baseRunDir();
 | 
				
			||||||
	QDir* shellRunDir();
 | 
						QDir* shellRunDir();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include <cerrno>
 | 
					#include <cerrno>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <qconfig.h>
 | 
					#include <qconfig.h>
 | 
				
			||||||
#include <qcontainerfwd.h>
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
| 
						 | 
					@ -177,14 +178,33 @@ int selectInstance(CommandState& cmd, InstanceLockInfo* instance, bool deadFallb
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (!cmd.instance.id->isEmpty()) {
 | 
						} else if (!cmd.instance.id->isEmpty()) {
 | 
				
			||||||
		path = basePath->filePath("by-pid");
 | 
							path = basePath->filePath("by-pid");
 | 
				
			||||||
		auto instances = QsPaths::collectInstances(path, deadFallback);
 | 
							auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		instances.removeIf([&](const InstanceLockInfo& info) {
 | 
							liveInstances.removeIf([&](const InstanceLockInfo& info) {
 | 
				
			||||||
			return !info.instance.instanceId.startsWith(*cmd.instance.id);
 | 
								return !info.instance.instanceId.startsWith(*cmd.instance.id);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							deadInstances.removeIf([&](const InstanceLockInfo& info) {
 | 
				
			||||||
 | 
								return !info.instance.instanceId.startsWith(*cmd.instance.id);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto instances = liveInstances.isEmpty() && deadFallback ? deadInstances : liveInstances;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (instances.isEmpty()) {
 | 
							if (instances.isEmpty()) {
 | 
				
			||||||
			qCInfo(logBare) << "No running instances start with" << *cmd.instance.id;
 | 
								if (deadFallback) {
 | 
				
			||||||
 | 
									qCInfo(logBare) << "No instances start with" << *cmd.instance.id;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									qCInfo(logBare) << "No running instances start with" << *cmd.instance.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!deadInstances.isEmpty()) {
 | 
				
			||||||
 | 
										qCInfo(logBare) << "Some dead instances match:";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for (auto& instance: deadInstances) {
 | 
				
			||||||
 | 
											qCInfo(logBare).noquote() << " -" << instance.instance.instanceId;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		} else if (instances.length() != 1) {
 | 
							} else if (instances.length() != 1) {
 | 
				
			||||||
			qCInfo(logBare) << "More than one instance starts with" << *cmd.instance.id;
 | 
								qCInfo(logBare) << "More than one instance starts with" << *cmd.instance.id;
 | 
				
			||||||
| 
						 | 
					@ -208,14 +228,29 @@ int selectInstance(CommandState& cmd, InstanceLockInfo* instance, bool deadFallb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		path = QDir(basePath->filePath("by-path")).filePath(pathId);
 | 
							path = QDir(basePath->filePath("by-path")).filePath(pathId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto instances = QsPaths::collectInstances(path, deadFallback);
 | 
							auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto instances = liveInstances;
 | 
				
			||||||
 | 
							if (instances.isEmpty() && deadFallback) {
 | 
				
			||||||
 | 
								instances = deadInstances;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sortInstances(
 | 
							sortInstances(
 | 
				
			||||||
		    instances,
 | 
							    instances,
 | 
				
			||||||
		    cmd.config.newest || (!instances.empty() && instances.first().pid == -1)
 | 
							    cmd.config.newest || (!instances.empty() && instances.first().pid == -1)
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (instances.isEmpty()) {
 | 
							if (instances.isEmpty()) {
 | 
				
			||||||
			qCInfo(logBare) << "No running instances for" << configFilePath;
 | 
								if (liveInstances.isEmpty() && deadInstances.length() > 1) {
 | 
				
			||||||
 | 
									qCInfo(logBare) << "No running instances for" << configFilePath;
 | 
				
			||||||
 | 
									qCInfo(logBare) << "Dead instances:";
 | 
				
			||||||
 | 
									sortInstances(deadInstances, cmd.config.newest);
 | 
				
			||||||
 | 
									for (auto& instance: deadInstances) {
 | 
				
			||||||
 | 
										qCInfo(logBare).noquote() << " -" << instance.instance.instanceId;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									qCInfo(logBare) << "No running instances for" << configFilePath;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,7 +311,18 @@ int listInstances(CommandState& cmd) {
 | 
				
			||||||
		path = QDir(basePath->filePath("by-path")).filePath(pathId);
 | 
							path = QDir(basePath->filePath("by-path")).filePath(pathId);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto instances = QsPaths::collectInstances(path);
 | 
						auto [liveInstances, deadInstances] = QsPaths::collectInstances(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sortInstances(liveInstances, cmd.config.newest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QList<InstanceLockInfo> instances;
 | 
				
			||||||
 | 
						if (cmd.instance.includeDead) {
 | 
				
			||||||
 | 
							sortInstances(deadInstances, cmd.config.newest);
 | 
				
			||||||
 | 
							instances = std::move(deadInstances);
 | 
				
			||||||
 | 
							instances.append(liveInstances);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							instances = std::move(liveInstances);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (instances.isEmpty()) {
 | 
						if (instances.isEmpty()) {
 | 
				
			||||||
		if (cmd.instance.all) {
 | 
							if (cmd.instance.all) {
 | 
				
			||||||
| 
						 | 
					@ -286,7 +332,6 @@ int listInstances(CommandState& cmd) {
 | 
				
			||||||
			qCInfo(logBare) << "Use --all to list all instances.";
 | 
								qCInfo(logBare) << "Use --all to list all instances.";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sortInstances(instances, cmd.config.newest);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cmd.output.json) {
 | 
							if (cmd.output.json) {
 | 
				
			||||||
			auto array = QJsonArray();
 | 
								auto array = QJsonArray();
 | 
				
			||||||
| 
						 | 
					@ -295,7 +340,7 @@ int listInstances(CommandState& cmd) {
 | 
				
			||||||
				auto json = QJsonObject();
 | 
									auto json = QJsonObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				json["id"] = instance.instance.instanceId;
 | 
									json["id"] = instance.instance.instanceId;
 | 
				
			||||||
				json["pid"] = instance.pid;
 | 
									json["pid"] = instance.instance.pid;
 | 
				
			||||||
				json["shell_id"] = instance.instance.shellId;
 | 
									json["shell_id"] = instance.instance.shellId;
 | 
				
			||||||
				json["config_path"] = instance.instance.configPath;
 | 
									json["config_path"] = instance.instance.configPath;
 | 
				
			||||||
				json["launch_time"] = instance.instance.launchTime.toString(Qt::ISODate);
 | 
									json["launch_time"] = instance.instance.launchTime.toString(Qt::ISODate);
 | 
				
			||||||
| 
						 | 
					@ -319,12 +364,18 @@ int listInstances(CommandState& cmd) {
 | 
				
			||||||
				                      .arg(remMinutes)
 | 
									                      .arg(remMinutes)
 | 
				
			||||||
				                      .arg(remSeconds);
 | 
									                      .arg(remSeconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									auto isDead = instance.pid == -1;
 | 
				
			||||||
 | 
									auto gray = !cmd.log.noColor && isDead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				qCInfo(logBare).noquote().nospace()
 | 
									qCInfo(logBare).noquote().nospace()
 | 
				
			||||||
				    << "Instance " << instance.instance.instanceId << ":\n"
 | 
									    << (gray ? "\033[90m" : "") << "Instance " << instance.instance.instanceId
 | 
				
			||||||
				    << "  Process ID: " << instance.pid << '\n'
 | 
									    << (isDead ? " (dead)" : "") << ":\n"
 | 
				
			||||||
 | 
									    << "  Process ID: " << instance.instance.pid << '\n'
 | 
				
			||||||
				    << "  Shell ID: " << instance.instance.shellId << '\n'
 | 
									    << "  Shell ID: " << instance.instance.shellId << '\n'
 | 
				
			||||||
				    << "  Config path: " << instance.instance.configPath << '\n'
 | 
									    << "  Config path: " << instance.instance.configPath << '\n'
 | 
				
			||||||
				    << "  Launch time: " << launchTimeStr << " (running for " << runtimeStr << ")\n";
 | 
									    << "  Launch time: " << launchTimeStr
 | 
				
			||||||
 | 
									    << (isDead ? "" : " (running for " + runtimeStr + ")") << '\n'
 | 
				
			||||||
 | 
									    << (gray ? "\033[0m" : "");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -128,6 +128,7 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio
 | 
				
			||||||
	    .configPath = args.configPath,
 | 
						    .configPath = args.configPath,
 | 
				
			||||||
	    .shellId = shellId,
 | 
						    .shellId = shellId,
 | 
				
			||||||
	    .launchTime = qs::Common::LAUNCH_TIME,
 | 
						    .launchTime = qs::Common::LAUNCH_TIME,
 | 
				
			||||||
 | 
						    .pid = getpid(),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if CRASH_REPORTER
 | 
					#if CRASH_REPORTER
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,7 @@ struct CommandState {
 | 
				
			||||||
		QStringOption id;
 | 
							QStringOption id;
 | 
				
			||||||
		pid_t pid = -1; // NOLINT (include)
 | 
							pid_t pid = -1; // NOLINT (include)
 | 
				
			||||||
		bool all = false;
 | 
							bool all = false;
 | 
				
			||||||
 | 
							bool includeDead = false;
 | 
				
			||||||
	} instance;
 | 
						} instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,6 +163,9 @@ int parseCommand(int argc, char** argv, CommandState& state) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sub->add_flag("-j,--json", state.output.json, "Output the list as a json.");
 | 
							sub->add_flag("-j,--json", state.output.json, "Output the list as a json.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sub->add_flag("--show-dead", state.instance.includeDead)
 | 
				
			||||||
 | 
							    ->description("Include dead instances in the list.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addConfigSelection(sub, true)->excludes(all);
 | 
							addConfigSelection(sub, true)->excludes(all);
 | 
				
			||||||
		addLoggingOptions(sub, false, true);
 | 
							addLoggingOptions(sub, false, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue