-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
auto-dark-light@gihaume: Version 1.2.0 (#6521)
* Add commands launching
- Loading branch information
1 parent
0e8845f
commit 5737a65
Showing
14 changed files
with
1,012 additions
and
226 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
...rk-light@gihaume/files/auto-dark-light@gihaume/lib/CLASSES HIERARCHY.drawio.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions
47
auto-dark-light@gihaume/files/auto-dark-light@gihaume/lib/commands_launcher.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
const launch_command = require('./lib/launch_command.js'); | ||
const { _ } = require('./lib/translator.js'); | ||
|
||
const {Gio, GLib} = imports.gi; | ||
|
||
class Commands_launcher { | ||
#callback_for_errors; | ||
|
||
/** | ||
* @param {Settings.XletSettingsBase} settings - The settings of the desk/applet. | ||
* @param {object} key_of_list - The keys of the settings' commands list. | ||
* @param {function(string): void} callback_for_errors - The callback with a message for when an error occurs. | ||
*/ | ||
constructor(settings, key_of_list, callback_for_errors) { | ||
settings.bindWithObject(this, key_of_list, "list"); | ||
this.#callback_for_errors = callback_for_errors; | ||
} | ||
|
||
async launch_commands() { | ||
for (const item of this.list) { | ||
const { name, active, expiry, command } = item; | ||
|
||
if (!active) | ||
continue; | ||
|
||
try { await launch_command(command, expiry); } | ||
catch (error) { | ||
let msg = `${_("the command")} '${name}' ${_("failed")}`; | ||
if (error instanceof GLib.ShellError) | ||
msg += ` ${_("due to a wrong format")}${_(":")} ${error.message}`; | ||
else | ||
if (error instanceof Gio.IOErrorEnum) { | ||
if (error.code === Gio.IOErrorEnum.TIMED_OUT) | ||
msg += ` ${_("due to time expiration")}`; | ||
else | ||
if (error.code === Gio.IOErrorEnum.FAILED) | ||
msg += ` ${_("with the following errors")}${_(":")} ${error.message}` | ||
} else | ||
msg += `${_(":")} ${error}` // full `error` object so we may see the stack trace | ||
|
||
this.#callback_for_errors(msg); | ||
} | ||
} | ||
} | ||
} | ||
|
||
module.exports = Commands_launcher; |
90 changes: 90 additions & 0 deletions
90
auto-dark-light@gihaume/files/auto-dark-light@gihaume/lib/launch_command.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
const {Gio, GLib} = imports.gi; | ||
|
||
Gio._promisify(Gio.Subprocess.prototype, 'communicate_utf8_async'); | ||
|
||
/** | ||
* Executes a command with a timeout and transmits any error on failure. | ||
* | ||
* @async | ||
* @param {string} command - The shell command to execute. | ||
* @param {number} [timeout_seconds=10] - The delay in seconds before cancelling the command. `0` means infinity/never. | ||
* @returns {Promise<void>} | ||
* @throws {GLib.ShellError} - If the command format is invalid. | ||
* @throws {Gio.IOErrorEnum.TIMED_OUT} - If the command is cancelled due to a timeout. | ||
* @throws {Gio.IOErrorEnum.FAILED} - If the command fails with a non-zero exit code. The error message is the `stderr` output if any, otherwise the exit status. | ||
*/ | ||
async function launch_command(command, timeout_seconds = 10) { | ||
const [_ok, argvp] = GLib.shell_parse_argv(command); // can throw GLib.ShellError | ||
|
||
const proc = new Gio.Subprocess({ | ||
argv: argvp, | ||
flags: Gio.SubprocessFlags.STDERR_PIPE | ||
}); | ||
|
||
const cancellable = Gio.Cancellable.new(); | ||
const cancellable_signal_handler_id = cancellable.connect( | ||
() => proc.force_exit() | ||
); | ||
|
||
proc.init(cancellable); | ||
|
||
let timeout_event_source_id; | ||
if (timeout_seconds !== 0) | ||
timeout_event_source_id = GLib.timeout_add_seconds( | ||
GLib.PRIORITY_DEFAULT, | ||
timeout_seconds, | ||
() => { | ||
cancellable.cancel(); | ||
timeout_event_source_id = undefined; | ||
} | ||
); | ||
|
||
try { | ||
const [_stdout, stderr] = await proc.communicate_utf8_async(null, null); | ||
|
||
if (cancellable.is_cancelled()) | ||
throw new Gio.IOErrorEnum({ | ||
code: Gio.IOErrorEnum.TIMED_OUT, | ||
message: "timed out" | ||
}); | ||
|
||
const exit_status = proc.get_exit_status(); | ||
if (exit_status !== 0) { | ||
throw new Gio.IOErrorEnum({ | ||
code: Gio.IOErrorEnum.FAILED, | ||
message: stderr ? stderr.trim() : "exit status: " + exit_status | ||
}); | ||
} | ||
} finally { | ||
cancellable.disconnect(cancellable_signal_handler_id); | ||
if (timeout_event_source_id) | ||
GLib.source_remove(timeout_event_source_id); | ||
} | ||
} | ||
|
||
module.exports = launch_command; | ||
|
||
// // Example usage: | ||
// | ||
// async function main() { | ||
// console.error("start"); | ||
// try { | ||
// await launch_command('./test', 5); | ||
// } catch (error) { | ||
// if (error instanceof GLib.ShellError) | ||
// console.error("command format: " + error.message); | ||
// else | ||
// if (error instanceof Gio.IOErrorEnum) { | ||
// if (error.code === Gio.IOErrorEnum.TIMED_OUT) | ||
// console.error("command aborted due to time out"); | ||
// else | ||
// if (error.code === Gio.IOErrorEnum.FAILED) | ||
// console.error("command failed: " + error.message); | ||
// } else | ||
// console.error(error); // full object so we can see the stack trace | ||
// } | ||
// } | ||
|
||
// main(); | ||
|
||
// new GLib.MainLoop(null, false).run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.