Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: sync method #681

Closed
jeremyben opened this issue Oct 1, 2023 · 2 comments · Fixed by #738
Closed

Feature request: sync method #681

jeremyben opened this issue Oct 1, 2023 · 2 comments · Fixed by #738
Labels
feature New feature or request

Comments

@jeremyben
Copy link

jeremyben commented Oct 1, 2023

I understand that a sync version of $ might not provide the same flexibility than the current async version, for example printing the ouput of a long running command before it ends.

But it might be beneficial for some short running commands that we usually wrap into a utility function, which do not blend in a regular control flow, where await everywhere becomes a pain.

An example:

/**
 * @param {string} bin
 * @returns {Promise<boolean>}
 */
export async function isAvailable(bin) {
	const { exitCode } = await $`command -v ${bin}`.nothrow()
	return !exitCode
}

// elsewhere

if (!(await isAvailable('ffmpeg'))) {
	// ...
}

Execa, who took inspiration from zx for its own $ utility, provides a sync method: https://github.com/sindresorhus/execa/tree/main#synccommand

@antonmedv antonmedv added the feature New feature or request label Oct 2, 2023
@DebasishBlockchain
Copy link

It's a valid concern, and there can be scenarios where having a synchronous version of a command execution library like shelljs (or the $ tagged template literal used in the example) can be beneficial for simplifying control flow in certain parts of your code.

If you'd like to contribute by adding a synchronous version, here's how you might approach it in JavaScript/TypeScript. Note that this is a simplified example, and you should consider adding error handling and handling more complex use cases based on your specific needs:

import shell from 'shelljs';

/**
 * Synchronously checks if a command is available.
 * @param {string} bin - The command to check.
 * @returns {boolean} - True if the command is available; otherwise, false.
 */
export function isAvailableSync(bin) {
    const result = shell.exec(`command -v ${bin}`, { silent: true });
    return result.code === 0;
}

// Usage
if (isAvailableSync('ffmpeg')) {
    // ...
}

In this example, we use the shelljs library to execute the command synchronously. The silent: true option is used to suppress output to the console, which is similar to the .nothrow() function in your original code.

Remember that synchronous code execution can block the event loop, so use this approach cautiously and only when necessary for specific use cases where synchronous execution is more appropriate.

@stevage
Copy link

stevage commented Dec 19, 2023

I'd also like to echo the call for some sync methods. One of the situations where it would have been useful is in a module which does a tiny bit of processing when it first initialises, along these lines:

import { $ } from `zx`
const host = $.sync`hostname`.stdout
if (host === ...)

The program as a whole isn't run through zx, so top-level await isn't an option, and I'm not even if that's possible in an imported module.

Requiring everything to be async sometimes introduces complexities like this that are solvable, but are just...annoying...when there's no benefit.

antongolub added a commit to antongolub/zx that referenced this issue Mar 18, 2024
antonmedv pushed a commit that referenced this issue Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants