Hacker News new | ask | show | jobs
by KajMagnus 1891 days ago
How do you pass arguments to your Make targets? Let's say you'd like to set `DB_USER` to "my_name", then, do you:

    make psql user=my_name  # ?
To me, having to type `user=` is very annoying, I want to do just `make psql my_name`.

Agreed that Make is nice :- ) My Makefile is not as nice as Make though o.O

> I'm not excited about writing a bash script

Bash scripts almost could be illegal :- ) I'm thinking about writing scripts in Deno in the future, instead

2 comments

Huh? But bash is super powerful? I can go from zero to a script that's production ready in like an hour with option support, help text, man pages, shell completion, signal handling that's portable to any system.

I also like Python for this but it's an absolute PITA to distribute scripts that support lots of different versions of python or need any dependencies not in your distro's repos.

Yes it's powerful, I agree about that. At the same time, it's not type safe (but Deno + Typescript would be), and the syntax is a bit funny, like the differences between `( (( [ [[` which I annoyingly often forget. One day, when I saw code like this:

    if [[ ${1:0:1} = '-' ]]; then
      ...
      set --
I got a bit annoyed, and said to myself that Bash scripts almost should be forbidden. I didn't know that syntax `${1:0:1}` and there wasn't really anything to websearch for — just different symbols.

Websearching for "bash bracket colon colon" something actually worked but it took a while. In a typed language, I'd just clicked a function and would have seen the docs, in an instant.

> from zero to a script that's production ready in like an hour with option support, help text, man pages, shell completion, signal handling that's portable to any system.

It seems you've been used Bash for quite a while. Then I'm guessing in your case, it's a good choice. Agreed that dependencies for Python or Deno or whatever else is annoying to have to include (the Deno runtime is sth like 50 - 60 MB if I remember correctly)

Lots of ways! So this is one of those things that's subtly quite interesting -- Make will both take all variables from the environment, and make them Make variables. So this command:

    $ USER=my_name make psql
The above example is the creation of a temporary ENV variable (assuming your shell supports this feature, it's equivalent to doing an export but only for that line), and the USER variable (accessed by using $(USER) or ${USER} in your makefile somewhere) will be automatically populated.

That is distinct from the following:

    $ make psql USER=my_name
What you've done there is actually make-specific, you're giving make a Make variable, so Make will know about $(USER)/${USER}, and it will also show up, because Make exposes it's variables to shells (each line is it's own shell) that is run[0]. So this Makefile:

   .PHONY: my-tgt

   my-tgt:
     echo -e "double dollar to print a bash var => $$MYVAR"
Produces the same thing -- $$MYVAR is actually a way to use a shell variable (the $ has to be escaped), but you get the same result putting USER= before and after:

    $ MYVAR=from-the-shell make my-tgt                                                                                                            
    double dollar to print a bash var => [from-the-shell]
    $ make my-tgt MYVAR=from-make                                                                                                                 
    double dollar to print a bash var => [from-make]
All that said, if you don't need to ever change the name then just make the target `psql-<username>` or `psql_username`, problem solved! For example, I use kubie on my kubernetes cluster, and I have explicitly named clusters, so when I want to enter a kubie context (just so I can avoid some typing), I run `make <cluster name>-kubie` and I'm off -- I didn't feel the need to do `make kubie CLUSTER=<cluster name>` though I easily could have. Here's what it actually looks like:

    mycluster-kubie:
     CLUSTER=mycluster $(KUBIE) ctx -f secrets/ansible/the.dns.name.of.my.server/var/lib/k0s/pki/admin.conf
I don't strictly need that CLUSTER=mycluster there, but if the command cared, then it could be easily "hard coded".

> Bash scripts almost could be illegal :- ) I'm thinking about writing scripts in Deno in the future, instead

Bash is super powerful, and some people are good at it, but it just hasn't stuck enough for me to be comfortable. Plus, it still feels like another language to be wrangled while Make's only purpose is to do the things (whatever that thing is) that build your software.

[EDIT] figured I might share some more nice pieces of software that I use and love (also so you don't think I'm just willy nilly checking in secrets to my repository):

- direnv[1] for managing local ENV settings in a given folder (like your project folder)

- git-crypt[2] for simple encryption of secrets in a git repository, with gpg support

- entr[3] it re-runs a given command when files change, really good for reducing feedback loops when working with tooling that doesn't have --watch/fsnotify functionality

[0]: https://www.gnu.org/software/make/manual/html_node/Environme...

[1]: https://direnv.net/docs/hook.html

[2]: https://www.agwa.name/projects/git-crypt/

[3]: https://eradman.com/entrproject/

Thanks for the reply & all info :- )

Actually, this: `USER=my_name make psql` and this: `make psql USER=my_name` I don't like that much: No command line completion of `USER=my_name`.

Makefile targets like `mycluster-kubie` are nice, although they can result in a combinatorial explosion (if one needs two or more parameters).

It seems to me that after all, it'll be Deno or maybe Rust "scripts" that I'll want to use, combined with Make — Make for building, and Deno for running things.

(Running = often, nice with command line completion. Building = less often.)

Thanks for the extra pieces of software :- ) Direnv looks nice, makes me nervous about security exploits though (seems it automatically parses a file in the current directory, sometimes provided by strangers, via a Git repo that maybe I just wanted to look at). Hmm, https://github.com/direnv/direnv/issues/23 "security considerations"

Git-crypt seems like a nice way to maybe distribute secrets for accessing one's CI environment :- )

Didn't know about entr. Currently I use inotifywait (from package inotify-tools in Debian)

No worries, no one really talks about it, but you see makefiles all over.

> Actually, this: `USER=my_name make psql` and this: `make psql USER=my_name` I don't like that much: No command line completion of `USER=my_name`.

> Makefile targets like `mycluster-kubie` are nice, although they can result in a combinatorial explosion (if one needs two or more parameters).

True, it's a bit inconvenient!

> It seems to me that after all, it'll be Deno or maybe Rust "scripts" that I'll want to use, combined with Make — Make for building, and Deno for running things.

This sounds wonderful -- the biggest downfall of make is when you start to try and do complicated things with it, so your usecase seems awesome. Make is good for that glue/orchestration in my opinion -- when you need to run pulumi/terraform right before you do some deno-scripted setup.

> Thanks for the extra pieces of software :- ) Direnv looks nice, makes me nervous about security exploits though (seems it automatically parses a file in the current directory, sometimes provided by strangers, via a Git repo that maybe I just wanted to look at). Hmm, https://github.com/direnv/direnv/issues/23 "security considerations"

Ahh so for that, I don't check in my `.envrc` folders but yeah that's certainly an issue -- whenever you encounter a `.envrc` you have to allow it though!

Every time you enter a folder that direnv hasn't seen before, or the file in there changes, you have to run `direnv allow` for it to be taken up.

> Didn't know about entr. Currently I use inotifywait (from package inotify-tools in Debian)

Ahh then that's probably just as good -- A friend showed me entr like.... 10+ years ago now and it's been a trusted tool on projects ever since, whenever the language/framework doesn't really have it, or I feel like some bit of work needs to be more streamlined/shorter feedback.

> Every time you enter a folder that direnv hasn't seen before, or the file in there changes, you have to run `direnv allow` for it to be taken up.

That sounds great, just like I would have hoped that it'd work. And, because of this: "or the file in there changes", in a way it's even safer than a Makefile — in that Make wouldn't notify me if the Makefile got changed, but Direnv does (and people might not remember to look at any Makefile diff after pulling from the repo). — Now I'm starting slightly thinking about if Direnv makes sense somewhere in my own project(s).