{"id":21670144,"url":"https://github.com/ubunatic/gjs-pipe","last_synced_at":"2026-05-18T17:41:56.020Z","repository":{"id":143880213,"uuid":"358145784","full_name":"ubunatic/gjs-pipe","owner":"ubunatic","description":"GjsPipe provides utilities to safely manage your Gio.Subprocess.","archived":false,"fork":false,"pushed_at":"2021-11-14T18:43:24.000Z","size":28,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-27T04:51:47.536Z","etag":null,"topics":["async","convenience","gio","gjs","glib","gnome","pipes","polyfill","subprocess"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ubunatic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSES/CC-BY-4.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-15T06:05:25.000Z","updated_at":"2021-11-14T16:56:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"1c56f097-3540-46d2-8aca-c6234c084dca","html_url":"https://github.com/ubunatic/gjs-pipe","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubunatic%2Fgjs-pipe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubunatic%2Fgjs-pipe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubunatic%2Fgjs-pipe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubunatic%2Fgjs-pipe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ubunatic","download_url":"https://codeload.github.com/ubunatic/gjs-pipe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244573493,"owners_count":20474717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","convenience","gio","gjs","glib","gnome","pipes","polyfill","subprocess"],"created_at":"2024-11-25T12:29:45.233Z","updated_at":"2026-05-18T17:41:50.995Z","avatar_url":"https://github.com/ubunatic.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GjsPipe\n\n![GjsPipe Logo](gjspipe.svg)\n\n[GjsPipe](https://github.com/ubunatic/gjs-pipe) provides utilities to safely manage your [Gio.Subprocess](https://gjs-docs.gnome.org/gio20~2.66p/gio.subprocess).\n\n\nThe library provides a [Pipe](lib/gjspipe/pipe.js) class for easily and safely creating\nprocesses in your `gjs` application and consuming the process\noutput line by line.\n\n## Basic Usage\n```js\n    // define a process to run a script in your system\n    let p = new Pipe('bash', '-c', 'while sleep 1; do echo \"looping\"; done')\n\n    // start the process and start reading output line by line\n    let cancel = p.start(line =\u003e print(line))\n\n    // if required, stop the pipe using the cancel function\n    cancel()\n\n    // That's all!\n```\n\n**WARNING**: Make sure to call `cancel` before exiting your `gjs` app.\n\nAn unclean exit of your `gjs` app can create orphaned processes in your system.\nUnfortunately `gjs` does not ensure that all instances of `Gio.Subprocess`\nare killed automatically on program exit.\n\n## Complete Usage Example\nHere is an example how to turn a system program on and off and consume its output.\n```js\n    const script = 'my-command'\n    const p = new Pipe('bash', '-c', script)\n    let cancel = null\n\n    function onResult(line) {\n        print(line)\n    }\n\n    function onExit(ok) {\n        if (ok) log(`pipe ${script} stopped`)\n        else    logError(new Error(`pipe ${script} failed, see logs for details`))\n    }\n\n    function onError(err) {\n        logError(err)\n        if (cancel) {\n            log(`pipe ${script} had errors, stopping pipe...`)\n            cancel()\n        }\n    }\n\n    function startPipe() {\n        return p.start(onResult, onExit, onError)\n    }\n\n    function toggle() {\n        if (cancel) { cancel(); cancel = null }\n        else        { cancel = startPipe()    }\n    }\n\n    toggleBtn.connect('toggled', (btn) =\u003e toggle())\n```\n\nThe `onExit` and `onError` callbacks are optional.\n\n* Without `onError` any errors will be logged via `logError`.\n* Without `onExit` the pipe may exit and fail silently.\n\n## Async Features\n\nIn addition to two simple `asyncTimeout` and `makeAsync` functions for running\nand awaiting any function asynchronously, this library also provides a\n`glibAsync` function to `await` async Glib start and finish calls.\n\n## Async Execution of Gio/GLib Functions\n\nAsync [Gio](https://gjs-docs.gnome.org/gio20~2.66p/) and\n[Glib](https://gjs-docs.gnome.org/glib20~2.66.1/) functions\nusually consist of a `\u003cfunc\u003e_async` and a `\u003cfunc\u003e_finish` for calling and handling\nasync IO. They do not return a `Promise` and thus cannot be awaited.\n\nGjsPipe provides **`glibAsync`** to mitigate this.\n\nInstead of callback-based execution, where errors may get lost in async nirvana:\n```js\nconst ctx = new Gio.Cancellable()\ntry {\n    proc.wait_check_async(ctx, (_, res) =\u003e {\n        try {\n            const ok = proc.wait_check_finish(res)\n        } catch (e) {\n            // async errors must be handled in the async handler functions\n            // and somehow be exposed the start-level using another callback\n            handleAsyncError(e)\n        }\n    }\n} catch (e) {\n    // only \"start\" errors can be catched\n}\n```\n\nYou can now use `async` and `await` and have errors thrown to where you started the execution:\n```js\ntry {\n    const ctx = new Gio.Cancellable()\n    const ok = await glibAsync(\n        (finish) =\u003e proc.wait_check_async(ctx, finish),  // GLib start logic\n        (_, res) =\u003e proc.wait_check_finish(res),         // GLib finish logic\n    )\n} catch (e) {\n    // all errors can handled at the start-level of the async function\n}\n```\n\n## License\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubunatic%2Fgjs-pipe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubunatic%2Fgjs-pipe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubunatic%2Fgjs-pipe/lists"}