Fix up checks in Makefile and make them portable by EliahKagan · Pull Request #1661 · gitpython-developers/GitPython (original) (raw)

Something you might find interesting is the $'\n works here' syntax in bash that helps with inserting newlines into echo at will.

In #1693 I took this further in what I would regard to be that direction, using two echo commands since the extra newline is at the edge:

-echo $'\nThe VERSION must be the same in all locations, and so must the HEAD and tag SHA' +echo +echo 'The VERSION must be the same in all locations, and so must the HEAD and tag SHA'

However, you might prefer the way with $' ' and \n for compactness. So I understand you may change it back (or request that I do so).

Another way to write this, which personally I do not think is as nice as either $' ' or using two separate echo commands, is:

echo -e '\nThe VERSION must...'

The reason I think the other approaches (including $' ' as you used here) are nicer is that the versatility of echo -e is more powerful than often intended. For example, this expands escape sequences in the value of var, which if untrusted, could cause problems, including giving strange instructions to some terminals that obscure output the user may rely on:

echo -e "2 loaves of bread\n3 eggs\n$var juice\na sponge"

In contrast, $" " exists, but it is unrelated to expanding escape sequences, so if one accidentally uses it, one finds out when the code is exercised.

POSIX permits echo to always, never, or sometimes, behave as though echo -e were used, and some echos have -e as the default behavior, sometimes allowing -E to turn it off. Actually, what POSIX actually permits is either behavior, or an arbitrary idiosyncratic combination of them. POSIX actually forbids -e and -E from being treated in these ways--they are supposed to be printed literally--but implementations widely treat them as options anyway. -n likewise may or may not be supported, though POSIX permits it, while also permitting it to be treated literally (or to have any other meaning).

For these and other reasons, echo is nonportable, but since echo in bash is a builtin, it is okay to use it in bash (so long as one does not write things like ... | xargs echo or find ... -exec echo ..., which use an external echo executable that may behave differently). It is for this reason that, in #1693, I've used printf in the init script, which as part of my proposed changes there is converted to be a POSIX shell script to support more systems. But this is inapplicable to the other scripts, which use bash's echo builtin without problems.

I also thought that maybe there would be a better place for them in some directory, but then I could also appreciate that some automation is so easily discoverable. It's probably OK to leave them as is for now.

I think we could document the Makefile in the readme and this would give sufficient discoverability, if in the future it is found useful to move them. But I have not included any such proposed change in #1693.

As for the .sh suffix, I am among the people who take the executable bit as indication of whether they are to be sourced or executed, so (at least to me) the intent is communicated clear enough.

This actually works remarkably better even than one might expect. The permissions system in Windows is very different from Unix-like systems, and nothing that really corresponds to Unix-style executable bits exists. But when one uses a Unix-style shell on Windows, such as the Git Bash shell, the available Unix-style utilities like ls handle this by guessing the executable bit from the hashbang. When one is not using a Unix-style shell, one typically cannot easily run a shell script, and one definitely cannot source one since it's the wrong language for the shell being used. So things tend to work out.

(This is separate from WSL: a system in WSL fully supports Unix-style permissions, though like any such operating system, it will not support them when using a Windows filesystem. Windows filesystems being used in a Unix-like system are typically--both when accessing files outside WSL from inside it, and when mounting an NTFS drive on an independent Unix-like operating system--mounted in such a way as to treat every file as having executable bits set. Then, the output of commands like ls -l is not illuminating, but also, for other reasons such as line endings, one should typically not work in a Git repository that way. For this reason I have included in #1693 an explicit mention in the readme that Windows users can invoke the init script from Git Bash. This suggestion is independent of actual changes made to that file, except inasmuch as both are with the aim of improving the experience on less well supported platforms.)

When thinking about it, at this point most of the work was already done and running make release locally isn't a problem, with the only 'inconvenience' that I have to type __token__ and then paste a passcode.

Publishing with GitHub Actions could potentially replace some of the logic in these scripts. For example, a workflow could be set up that builds and published to PyPI when a release is made on GitHub, or when a push creates a tag, comes from a PR with a particular label, etc. (If one of those latter triggers is used, the workflow could even create the GitHub release as well, populating it with the default description or with a custom-generated one.)

Here's an example of building and publishing to PyPI when a release is made on GitHub (though that project uses the dependency manager poetry to build the package). This is technically separate from the use of trusted publishing, in that publishing could be done in the workflow by running a twine command supplied with access credentials sourced from a repository-level GitHub Actions secret. However, these days, trusted publishing is increasingly used, which avoids the need to store PyPI access credentials in a CI secret store.

These few seconds could be saved at the expense of complexity, abstraction, and giving some secrets to the cloud.

I think this is strictly speaking true: any user who has the power to make arbitrary changes to the repository can use that power to cause a release to be published to PyPI, when trusted publishing is used. However, no PyPI secret has to be stored in the repository--changes are validated as having originated from the GitHub repository (and more specifically as from a CI job produced from a particular workflow whose file name has been put in via the PyPI web interface while setting it up), without involving separate stored credentials.