forked from quickshell/quickshell
		
	feat(process): add Process.environment
This commit is contained in:
		
							parent
							
								
									65ad2a9877
								
							
						
					
					
						commit
						e06b07ac01
					
				
					 3 changed files with 115 additions and 20 deletions
				
			
		
							
								
								
									
										2
									
								
								docs
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								docs
									
										
									
									
									
								
							| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
Subproject commit 8b40a464af5c1338d842e61f8ec517d142454cbc
 | 
					Subproject commit 1ca13d9ffded3fbddb0380c0d0df85304065efa9
 | 
				
			||||||
| 
						 | 
					@ -5,10 +5,12 @@
 | 
				
			||||||
#include <qdir.h>
 | 
					#include <qdir.h>
 | 
				
			||||||
#include <qlist.h>
 | 
					#include <qlist.h>
 | 
				
			||||||
#include <qlogging.h>
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qmap.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qprocess.h>
 | 
					#include <qprocess.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qvariant.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../core/qmlglobal.hpp"
 | 
					#include "../core/qmlglobal.hpp"
 | 
				
			||||||
#include "datastream.hpp"
 | 
					#include "datastream.hpp"
 | 
				
			||||||
| 
						 | 
					@ -35,6 +37,16 @@ QVariant Process::pid() const {
 | 
				
			||||||
	return QVariant::fromValue(this->process->processId());
 | 
						return QVariant::fromValue(this->process->processId());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QList<QString> Process::command() const { return this->mCommand; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Process::setCommand(QList<QString> command) {
 | 
				
			||||||
 | 
						if (this->mCommand == command) return;
 | 
				
			||||||
 | 
						this->mCommand = std::move(command);
 | 
				
			||||||
 | 
						emit this->commandChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->startProcessIfReady();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString Process::workingDirectory() const {
 | 
					QString Process::workingDirectory() const {
 | 
				
			||||||
	if (this->mWorkingDirectory.isEmpty()) return QDir::current().absolutePath();
 | 
						if (this->mWorkingDirectory.isEmpty()) return QDir::current().absolutePath();
 | 
				
			||||||
	else return this->mWorkingDirectory;
 | 
						else return this->mWorkingDirectory;
 | 
				
			||||||
| 
						 | 
					@ -54,14 +66,20 @@ void Process::onGlobalWorkingDirectoryChanged() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QList<QString> Process::command() const { return this->mCommand; }
 | 
					QMap<QString, QVariant> Process::environment() const { return this->mEnvironment; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Process::setCommand(QList<QString> command) {
 | 
					void Process::setEnvironment(QMap<QString, QVariant> environment) {
 | 
				
			||||||
	if (this->mCommand == command) return;
 | 
						if (environment == this->mEnvironment) return;
 | 
				
			||||||
	this->mCommand = std::move(command);
 | 
						this->mEnvironment = std::move(environment);
 | 
				
			||||||
	emit this->commandChanged();
 | 
						emit this->environmentChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->startProcessIfReady();
 | 
					bool Process::environmentCleared() const { return this->mClearEnvironment; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Process::setEnvironmentCleared(bool cleared) {
 | 
				
			||||||
 | 
						if (cleared == this->mClearEnvironment) return;
 | 
				
			||||||
 | 
						this->mClearEnvironment = cleared;
 | 
				
			||||||
 | 
						emit this->environmentClearChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DataStreamParser* Process::stdoutParser() const { return this->mStdoutParser; }
 | 
					DataStreamParser* Process::stdoutParser() const { return this->mStdoutParser; }
 | 
				
			||||||
| 
						 | 
					@ -167,8 +185,31 @@ void Process::startProcessIfReady() {
 | 
				
			||||||
	if (this->mStderrParser == nullptr) this->process->closeReadChannel(QProcess::StandardError);
 | 
						if (this->mStderrParser == nullptr) this->process->closeReadChannel(QProcess::StandardError);
 | 
				
			||||||
	if (!this->mStdinEnabled) this->process->closeWriteChannel();
 | 
						if (!this->mStdinEnabled) this->process->closeWriteChannel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!this->mWorkingDirectory.isEmpty())
 | 
						if (!this->mWorkingDirectory.isEmpty()) {
 | 
				
			||||||
		this->process->setWorkingDirectory(this->mWorkingDirectory);
 | 
							this->process->setWorkingDirectory(this->mWorkingDirectory);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!this->mEnvironment.isEmpty() || this->mClearEnvironment) {
 | 
				
			||||||
 | 
							auto sysenv = QProcessEnvironment::systemEnvironment();
 | 
				
			||||||
 | 
							auto env = this->mClearEnvironment ? QProcessEnvironment() : sysenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto& name: this->mEnvironment.keys()) {
 | 
				
			||||||
 | 
								auto value = this->mEnvironment.value(name);
 | 
				
			||||||
 | 
								if (!value.isValid()) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this->mClearEnvironment) {
 | 
				
			||||||
 | 
									if (value.isNull()) {
 | 
				
			||||||
 | 
										if (sysenv.contains(name)) env.insert(name, sysenv.value(name));
 | 
				
			||||||
 | 
									} else env.insert(name, value.toString());
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									if (value.isNull()) env.remove(name);
 | 
				
			||||||
 | 
									else env.insert(name, value.toString());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->process->setProcessEnvironment(env);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->process->start(cmd, args);
 | 
						this->process->start(cmd, args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qprocess.h>
 | 
					#include <qprocess.h>
 | 
				
			||||||
#include <qqmlintegration.h>
 | 
					#include <qqmlintegration.h>
 | 
				
			||||||
| 
						 | 
					@ -42,14 +43,6 @@ class Process: public QObject {
 | 
				
			||||||
	Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged);
 | 
						Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged);
 | 
				
			||||||
	/// The process ID of the running process or `null` if `running` is false.
 | 
						/// The process ID of the running process or `null` if `running` is false.
 | 
				
			||||||
	Q_PROPERTY(QVariant pid READ pid NOTIFY pidChanged);
 | 
						Q_PROPERTY(QVariant pid READ pid NOTIFY pidChanged);
 | 
				
			||||||
	/// The working directory of the process. Defaults to [quickshell's working directory].
 | 
					 | 
				
			||||||
	///
 | 
					 | 
				
			||||||
	/// If the process is already running changing this property will affect the next
 | 
					 | 
				
			||||||
	/// started process. If the property has been changed after starting a process it will
 | 
					 | 
				
			||||||
	/// return the new value, not the one for the currently running process.
 | 
					 | 
				
			||||||
	///
 | 
					 | 
				
			||||||
	/// [quickshell's working directory]: ../../quickshell/quickshell#prop.workingDirectory
 | 
					 | 
				
			||||||
	Q_PROPERTY(QString workingDirectory READ workingDirectory WRITE setWorkingDirectory NOTIFY workingDirectoryChanged);
 | 
					 | 
				
			||||||
	/// The command to execute.
 | 
						/// The command to execute.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// If the process is already running changing this property will affect the next
 | 
						/// If the process is already running changing this property will affect the next
 | 
				
			||||||
| 
						 | 
					@ -59,6 +52,57 @@ class Process: public QObject {
 | 
				
			||||||
	/// > [!INFO] You can use `["sh", "-c", <your command>]` to execute your command with
 | 
						/// > [!INFO] You can use `["sh", "-c", <your command>]` to execute your command with
 | 
				
			||||||
	/// > the system shell.
 | 
						/// > the system shell.
 | 
				
			||||||
	Q_PROPERTY(QList<QString> command READ command WRITE setCommand NOTIFY commandChanged);
 | 
						Q_PROPERTY(QList<QString> command READ command WRITE setCommand NOTIFY commandChanged);
 | 
				
			||||||
 | 
						/// The working directory of the process. Defaults to [quickshell's working directory].
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If the process is already running changing this property will affect the next
 | 
				
			||||||
 | 
						/// started process. If the property has been changed after starting a process it will
 | 
				
			||||||
 | 
						/// return the new value, not the one for the currently running process.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// [quickshell's working directory]: ../../quickshell/quickshell#prop.workingDirectory
 | 
				
			||||||
 | 
						Q_PROPERTY(QString workingDirectory READ workingDirectory WRITE setWorkingDirectory NOTIFY workingDirectoryChanged);
 | 
				
			||||||
 | 
						/// Environment of the executed process.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// This is a javascript object (json). Environment variables can be added by setting
 | 
				
			||||||
 | 
						/// them to a string and removed by setting them to null (except when [clearEnvironment] is true,
 | 
				
			||||||
 | 
						/// in which case this behavior is inverted, see [clearEnvironment] for details).
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// ```qml
 | 
				
			||||||
 | 
						/// environment: ({
 | 
				
			||||||
 | 
						///   ADDED: "value",
 | 
				
			||||||
 | 
						///   REMOVED: null,
 | 
				
			||||||
 | 
						///   "i'm different": "value",
 | 
				
			||||||
 | 
						/// })
 | 
				
			||||||
 | 
						/// ```
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// > [!INFO] You need to wrap the returned object in () otherwise it won't parse due to javascript ambiguity.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If the process is already running changing this property will affect the next
 | 
				
			||||||
 | 
						/// started process. If the property has been changed after starting a process it will
 | 
				
			||||||
 | 
						/// return the new value, not the one for the currently running process.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// [clearEnvironment]: #prop.clearEnvironment
 | 
				
			||||||
 | 
						Q_PROPERTY(QMap<QString, QVariant> environment READ environment WRITE setEnvironment NOTIFY environmentChanged);
 | 
				
			||||||
 | 
						/// If the process's environment should be cleared prior to applying [environment](#prop.environment).
 | 
				
			||||||
 | 
						/// Defaults to false.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If true, all environment variables will be removed before the [environment](#prop.environment)
 | 
				
			||||||
 | 
						/// object is applied, meaning the variables listed will be the only ones visible to the process.
 | 
				
			||||||
 | 
						/// This changes the behavior of `null` to pass in the system value of the variable if present instead
 | 
				
			||||||
 | 
						/// of removing it.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// ```qml
 | 
				
			||||||
 | 
						/// clearEnvironment: true
 | 
				
			||||||
 | 
						/// environment: ({
 | 
				
			||||||
 | 
						///   ADDED: "value",
 | 
				
			||||||
 | 
						///   PASSED_FROM_SYSTEM: null,
 | 
				
			||||||
 | 
						/// })
 | 
				
			||||||
 | 
						/// ```
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If the process is already running changing this property will affect the next
 | 
				
			||||||
 | 
						/// started process. If the property has been changed after starting a process it will
 | 
				
			||||||
 | 
						/// return the new value, not the one for the currently running process.
 | 
				
			||||||
 | 
						Q_PROPERTY(bool clearEnvironment READ environmentCleared WRITE setEnvironmentCleared NOTIFY environmentClearChanged);
 | 
				
			||||||
	/// The parser for stdout. If the parser is null the process's stdout channel will be closed
 | 
						/// The parser for stdout. If the parser is null the process's stdout channel will be closed
 | 
				
			||||||
	/// and no further data will be read, even if a new parser is attached.
 | 
						/// and no further data will be read, even if a new parser is attached.
 | 
				
			||||||
	Q_PROPERTY(DataStreamParser* stdout READ stdoutParser WRITE setStdoutParser NOTIFY stdoutParserChanged);
 | 
						Q_PROPERTY(DataStreamParser* stdout READ stdoutParser WRITE setStdoutParser NOTIFY stdoutParserChanged);
 | 
				
			||||||
| 
						 | 
					@ -85,11 +129,17 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] QVariant pid() const;
 | 
						[[nodiscard]] QVariant pid() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] QList<QString> command() const;
 | 
				
			||||||
 | 
						void setCommand(QList<QString> command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] QString workingDirectory() const;
 | 
						[[nodiscard]] QString workingDirectory() const;
 | 
				
			||||||
	void setWorkingDirectory(const QString& workingDirectory);
 | 
						void setWorkingDirectory(const QString& workingDirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] QList<QString> command() const;
 | 
						[[nodiscard]] QMap<QString, QVariant> environment() const;
 | 
				
			||||||
	void setCommand(QList<QString> command);
 | 
						void setEnvironment(QMap<QString, QVariant> environment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool environmentCleared() const;
 | 
				
			||||||
 | 
						void setEnvironmentCleared(bool cleared);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] DataStreamParser* stdoutParser() const;
 | 
						[[nodiscard]] DataStreamParser* stdoutParser() const;
 | 
				
			||||||
	void setStdoutParser(DataStreamParser* parser);
 | 
						void setStdoutParser(DataStreamParser* parser);
 | 
				
			||||||
| 
						 | 
					@ -106,8 +156,10 @@ signals:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void runningChanged();
 | 
						void runningChanged();
 | 
				
			||||||
	void pidChanged();
 | 
						void pidChanged();
 | 
				
			||||||
	void workingDirectoryChanged();
 | 
					 | 
				
			||||||
	void commandChanged();
 | 
						void commandChanged();
 | 
				
			||||||
 | 
						void workingDirectoryChanged();
 | 
				
			||||||
 | 
						void environmentChanged();
 | 
				
			||||||
 | 
						void environmentClearChanged();
 | 
				
			||||||
	void stdoutParserChanged();
 | 
						void stdoutParserChanged();
 | 
				
			||||||
	void stderrParserChanged();
 | 
						void stderrParserChanged();
 | 
				
			||||||
	void stdinEnabledChanged();
 | 
						void stdinEnabledChanged();
 | 
				
			||||||
| 
						 | 
					@ -126,8 +178,9 @@ private:
 | 
				
			||||||
	void startProcessIfReady();
 | 
						void startProcessIfReady();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QProcess* process = nullptr;
 | 
						QProcess* process = nullptr;
 | 
				
			||||||
	QString mWorkingDirectory;
 | 
					 | 
				
			||||||
	QList<QString> mCommand;
 | 
						QList<QString> mCommand;
 | 
				
			||||||
 | 
						QString mWorkingDirectory;
 | 
				
			||||||
 | 
						QMap<QString, QVariant> mEnvironment;
 | 
				
			||||||
	DataStreamParser* mStdoutParser = nullptr;
 | 
						DataStreamParser* mStdoutParser = nullptr;
 | 
				
			||||||
	DataStreamParser* mStderrParser = nullptr;
 | 
						DataStreamParser* mStderrParser = nullptr;
 | 
				
			||||||
	QByteArray stdoutBuffer;
 | 
						QByteArray stdoutBuffer;
 | 
				
			||||||
| 
						 | 
					@ -135,4 +188,5 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool targetRunning = false;
 | 
						bool targetRunning = false;
 | 
				
			||||||
	bool mStdinEnabled = false;
 | 
						bool mStdinEnabled = false;
 | 
				
			||||||
 | 
						bool mClearEnvironment = false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue