[HN Gopher] Scriptisto: "Shebang interpreter" that enables writi...
___________________________________________________________________
Scriptisto: "Shebang interpreter" that enables writing scripts in
compiled langs
Author : ronjouch
Score : 43 points
Date : 2024-02-06 10:41 UTC (1 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| ronjouch wrote:
| Via Simon Willison's excellent blog:
| https://simonwillison.net/2024/Feb/6/scriptisto/ , via lobste.rs:
| https://lobste.rs/s/ccssqq/scriptisto_writing_one_file_scrip...
| UncleOxidant wrote:
| It looks like it invokes the compiler every time the script is
| run? That's nice if you've changed the file, but takes extra time
| if you haven't. It seems neat at first, but I guess I don't see
| the advantage over just compiling to an executable and then
| running that.
| ComputerGuru wrote:
| I don't want to spam the link, but I actually _just_ posted a
| top-level comment to a version of this I published back in 2020
| that does caching and cache invalidation, using the hash of the
| script as the key for the compiled output path.
|
| EDIT:
|
| Actually, that was how the original version worked, but it had
| the limitation that once the script changed you could no longer
| determine the path to the _previous_ executable output to
| delete, so you could end up accumulating a lot of defunct
| binaries. Now the hash is stored alongside the target.
| actinium226 wrote:
| There was some mention in the wiki about caching the result and
| rebuilding it on change, so it seems well thought out from that
| perspective.
| catketch wrote:
| it does some dependency checking, so no compiler invocation if
| the source isn't changed, the binary is cached
| ComputerGuru wrote:
| For the rustaceans in the crowd:
|
| It's not a universal "for all compiled langs," but I published a
| two-liner [0] with zero (non-standard) dependencies or pre-
| requisites that can be copy-and-pasted to the top of any rust
| code to turn it into an executable script (cached! also correctly
| cache-invalidating!) back in 2020.
|
| It even lets you optionally omit the `fn main() { ... }`
| surrounding your code as well, if you _really_ want to feel like
| you 're just shell scripting <insert appropriate emoji here>.
|
| It's an example of "polyglot source code" that is valid under two
| languages at once (in this case, standard sh and rust), (ab)using
| the rust `#[allow(...)]` "macro" to do double-duty as a shell
| script comment opener.
|
| [0] https://neosmart.net/blog/self-compiling-rust-code/
| qznc wrote:
| Nice hack! Would it have been possible back then to use cargo
| to pull in some dependencies?
|
| The clean solution of cargo script is here:
| https://github.com/rust-lang/cargo/issues/12207
|
| Following the links, the RFC contains a nice list of similar
| tools: https://rust-lang.github.io/rfcs/3424-cargo-
| script.html#prio...
| ComputerGuru wrote:
| Thanks!
|
| > Would it have been possible back then to use cargo to pull
| in some dependencies?
|
| Not at the time, at least not that I know of.
|
| I wonder if it's possible to get a link to this solution
| added to that "prior art" section.
| elitepleb wrote:
| not too dissimilar an idea from Tom Duff's com executable
| https://web.archive.org/web/20210204050841/http://www.iq0.co...
| hawski wrote:
| I prefer to take advantage of the fact that without a proper
| shebang the file will be first executed by the shell. Then it is
| easy to do almost whatever you want.
|
| For example I put this in front of my test C files:
| #if 0 set -e; [ "$0" -nt "$0.bin" ] && gcc -Wall
| -Wextra -pedantic -std=c99 "$0" -o "$0.bin" exec "$0.bin"
| "$@" #endif
|
| I call those: polyglot shell scripts. All my examples are valid
| files for the language while working as shell scripts at the same
| time.
|
| In the past when Python 3 was still not obviously there and under
| different names it was once useful for me to have this on top of
| a python script: "set" "-e" "exec" "$(for p
| in python3.7 python3 python; do which p && break; done)" "$0"
| "$@"
|
| It works, because Python doesn't care about stray strings.
|
| You can also use the trick with Makefiles, although I never
| needed to use it: #\ set -e #\
| exec make -f "$0" "$@"
|
| This is not a useful example, but it works. This works, because
| make will treat slash followed by a new-line as a comment
| continuation and bash will ignore it.
| metadat wrote:
| I appreciate a good hack more than most, but this is the kind
| of cleverness which makes life hell for anyone else who needs
| to understand what the fuck is happening and why.
|
| At least with TFAs shebang at the top of the file, it kind of
| gives a clue. Upon reflection, I don't feel great about either
| way, haha. Even if it makes sense to me, it'll be a little too
| sneaky for most.
| lambdaba wrote:
| Somewhat related: nix-shell supports an additional shebang,
| allowing summoning of any combination of packages, to be made
| available inside a script. An example from the docs[1]:
| #!/usr/bin/env nix-shell #![allow()] /* #!nix-shell
| -i bash -p rustc rsfile="$(readlink -f $0)"
| binfile="/tmp/$(basename "$rsfile").bin" rustc "$rsfile" -o
| "$binfile" --edition=2021 && exec "$binfile" $@ || exit $?
| */ fn main() { for argument in
| std::env::args().skip(1) { println!("{}",
| argument); }; println!("{}",
| std::env::var("HOME").expect("")); }
|
| and another: #! /usr/bin/env nix-shell #!
| nix-shell -p "haskellPackages.ghcWithPackages (p: with p;
| [turtle])" -i runghc {-# LANGUAGE OverloadedStrings
| #-} import Turtle main = echo "Hello
| world!"
|
| 1. https://nixos.wiki/wiki/Nix-shell_shebang
| 12_throw_away wrote:
| In my experience, writing small but critical shell-script-style
| mini-programs in rust can actually be a really good idea. The
| biggest drawback is, IMO, all the overhead of setting up an
| entire crate just to compile a tiny script, so I'm really happy
| to see projects like this (and other tools [1]) for this
| workflow.
|
| [1] https://rust-lang.github.io/rfcs/3424-cargo-
| script.html#prio...
| IshKebab wrote:
| The problem with these systems is third party dependencies and
| IDE support. You really want to be able to use third party
| dependencies, and have IDEs know about them.
|
| The only systems I know of that do that properly are Deno and I
| believe F#, though I haven't tried the latter.
|
| Unfortunately Deno has a stupid issue where `deno run` will check
| for updates and print a "new version of Deno is available"
| message which rather sours the otherwise great experience of
| using it for shell scripting.
| TylerE wrote:
| This is one of the things that drive me nuts about open source
| projects. Sane defaults are critical to onboarding. Yet default
| configs seem to mostly be setup for maximum pedantry.
| foobarqux wrote:
| For python #!/usr/bin/env -S
| PIP_RUN_RETENTION_STRATEGY=persist pip-run #
| Requirements: # pendulum>=1.0.0 # requests
| import requests print('hello')
| mirekrusin wrote:
| Executable, single files with dependency specification should
| have first class support in all languages.
|
| But that's not going to happen.
|
| So next best option is probably weirdly a markdown file executor
| which runs triple quoted blocks.
|
| The upside is that you could mix different languages, which is
| interesting.
___________________________________________________________________
(page generated 2024-02-07 23:00 UTC)