[HN Gopher] Just: Just a Command Runner
___________________________________________________________________
Just: Just a Command Runner
Author : thunderbong
Score : 574 points
Date : 2024-12-07 17:11 UTC (1 days ago)
(HTM) web link (just.systems)
(TXT) w3m dump (just.systems)
| golly_ned wrote:
| I've used Just at a workplace on a project I didn't start. It
| seemed slightly simpler than make when putting together task
| dependencies. But I couldn't figure out what justifies using it
| over make.
| qznc wrote:
| The manual lists the reasons why using it over make:
| https://just.systems/man/en/
|
| The question is if those reasons are convincing to someone. The
| big advantage of Make is that it is probably already installed.
| erichdongubler wrote:
| > The big advantage of Make is that it is probably already
| installed.
|
| ...unless you're on Windows, like me!
| deaddodo wrote:
| Make is installed on Windows, if you install Microsoft's
| C/C++ dev stack (typically via installing Visual Studio).
| They just use nmake instead of GNU make. They also include
| Cmake these days, as it's the common cross platform option.
| BeetleB wrote:
| > if you install Microsoft's C/C++ dev stack (typically
| via installing Visual Studio).
|
| So I have to install this huge dependency just to use
| make, when my project is in Python?
|
| Way easier to install just :-)
| deaddodo wrote:
| You wouldn't use GNU Make (the thing that comes for
| "default" on Linux) with Python either.
|
| What a weird way to converse.
| BeetleB wrote:
| > You wouldn't use GNU Make (the thing that comes for
| "default" on Linux) with Python either.
|
| But people _do_ use Make all the time for Python projects
| - as a command runner. Pelican projects, for example,
| come with a Makefile to start the server, publish, etc.
|
| The whole point of this submission is that many, many
| people use Makefiles not for incremental builds, but as a
| convenient place to store commonly used commands. And
| just is a better and simpler tool than make for that. If
| you're on Windows, it's a pain to install make, compared
| to installing just.
| ttyprintk wrote:
| Busybox comes with a vestigial make. I wager git might.
| Those are both in winget.
| fragmede wrote:
| What does it offer over bazel?
| peterldowns wrote:
| Not making you want to shoot yourself in the head.
|
| It does one thing very well, and it has well-written and
| _useful_ documentation.
|
| It literally just runs commands in a convenient way.
| fragmede wrote:
| how well does it cache across a build farm?
| pdimitar wrote:
| Did you miss the part that says "it just runs commands in
| a convenient way" and "it is not a build system"?
| 12_throw_away wrote:
| It's not a build system, it's a command runner, it is for
| different use cases
| hgs3 wrote:
| The manual states that "just is a command runner, not a build
| system," and mentions "no need for .PHONY recipes!" This
| seems to suggest that there's no way to prevent Just from
| rebuilding targets, even if they are up-to-date. For me, one
| of the key advantages of using Make is its support for
| incremental builds, which is a major distinction from using a
| plain shell script to run some commands.
| klabb3 wrote:
| Maybe it's the stacks I'm using, but I've always had
| incremental happen with language-native tooling like `go`
| or `cargo`. So for me at least, having lazy eval features
| like that would be an unnecessary increase in scope and
| complexity. With Just, I can just throw together different
| commands and it just works cross platform. I love it.
|
| I much prefer that than the other way, ie letting language
| tooling become command runners (looking at you npm). That's
| the worst of both worlds.
| hgs3 wrote:
| > I've always had incremental happen with language-native
| tooling like `go` or `cargo`
|
| That makes sense, but for me, Make is incredibly useful
| for incremental file processing outside of programming.
| I've written tiny Makefiles that use glob patterns to
| batch-convert thousands of SVGs into PNGs and WebPs, but
| only for the modified SVG files. I've used Make to batch-
| convert modified LaTeX files to PDFs and render modified
| Blender projects into WebM videos for the web. Rendering
| videos is _very_ time-consuming, so only rendering
| modified video files is a huge win.
| guipsp wrote:
| If you need incrementalism, Just is not for you.
| pdimitar wrote:
| The programming languages that I use don't need to be told
| to not rebuild from scratch so yours is a pretty strange
| argument.
| BeetleB wrote:
| Your first sentence says:
|
| > just is a command runner, not a build system
|
| And then you go ahead and complain that it is poor at
| building.
|
| If you need a build tool, don't use just. Use make or
| something else. The purpose of just is to stop putting non-
| build stuff in Makefiles. And of course, it has a nice set
| of features that make doesn't.
| hgs3 wrote:
| I think there's been a misunderstanding.
|
| > Your first sentence says
|
| My first sentence was me quoting the Just manual and my
| second sentence was my observation about what that
| suggests. I wasn't asserting whether it's true or not,
| just sharing my interpretation, as I'm not familiar with
| Just.
|
| > And then you go ahead and complain that it is poor at
| building.
|
| I did not "complain" I stated that incremental builds,
| regardless of whether Just has them or not, is one
| feature I personally like about Make.
|
| Going by the responses I received, Just does not appear
| to support incremental builds and a simple
| acknowledgement, minus the vitriol, would have sufficed.
| badsectoracula wrote:
| > You can disable this behavior for specific targets using
| make's built-in .PHONY target name, but the syntax is verbose
| and can be hard to remember.
|
| I think this is overstating things a bit. I first read
| `.PHONY` in a Makefile while i was a teenager and i figured
| out what it does just by looking at it in practice.
|
| Makefiles do have some weirdness (e.g. tab being part of the
| syntax) but `.PHONY` is not one of them.
| nucleardog wrote:
| make is a build system and has a lot of complexity in it to
| make it optimal (or at least attempt to) for that use case.
|
| just is a "command runner" and functionally the equivalent of
| packing up a folder full of short scripts into a single file
| with a little bit of sugar on top. (E.g., by default every
| script is executed with the CWD being the folder the justfile
| is in so you don't need to go search for that stackoverflow
| answer about getting the script's folder and paste that in the
| top of every script.)
|
| If you use just as a build system, you're going to end up
| reimplementing half of make. If you try and use make as a
| command runner, you end up fighting it in many ways because
| you're not "building" things.
|
| I've generally found the most value in just in situations where
| shell is a good way to implement whatever I"m doing but it's
| grown large enough that it could benefit from some greater
| organization.
| 12_throw_away wrote:
| > search for that stackoverflow answer about getting the
| script's folder and paste that in the top of every script
|
| Ah, a fellow Person of Culture.
| BeetleB wrote:
| Having recipes just for Windows/Linux.
|
| Being able to write your recipes in another language.
|
| Not having to be in the directory where the Makefile resides.
|
| Being able to call a recipe _after_ the current recipe with &&
| syntax.
|
| Overall lower mental burden than make. make is very complex.
| just is very simple. If you know neither of the two, you'll get
| going much faster with just.
| clintonc wrote:
| For me, it's a fit-for-purpose issue. Make is great when you're
| creating artifacts and want to rebuild based on changes. Just
| is a task runner, so while there's a notion of dependent tasks,
| there's no notion of dependent artifacts. If you're using a lot
| of .PHONY targets in a Makefile, you're mostly using it as a
| task runner -- it works, but it's not ergonomic.
|
| I like that just will search upward for the nearest justfile,
| and run the command with its directory as the working directory
| (optional -- https://just.systems/man/en/attributes.html --
| with fallback available --
| https://just.systems/man/en/fallback-to-parent-
| justfiles.htm...). For example, I might use something like
| `just devserver` or `just testfe` to trigger commands, or `just
| upload` to push some assets -- these commands work from
| anywhere within the project.
|
| My life wouldn't be _that_ different if I just had to use Make
| (and I still use Make for some tasks), but I like having a
| language-agnostic, more ergonomic task runner.
| peterldowns wrote:
| As a heavy Just user, I agree with all of this -- great
| answer.
| nrclark wrote:
| Just a quick note for interested readers: you don't need to
| explicitly mark things as .PHONY in make, unless your
| Makefile lives next to files/folders with the same name as
| your targets. So unless you had some file called "install" in
| the same folder, you wouldn't need to have something like
| ".PHONY: install".
| vbezhenar wrote:
| That's the right thing to do, so you should. Relying on
| implicit condition of specific file missing in current
| directory is very wrong IMO.
| metaltyphoon wrote:
| The moment you need to build the same software on windows its
| already justified IMO
| richie_adler wrote:
| For me is not needing to chain a lot of commands with && to
| ensure that it fails with the first command that fails. With
| just, if one of the commands of the recipe fails, it stops.
| bsnnkv wrote:
| This is one of the most important pieces of software in my
| development stack that "just" gets out of the way and does what
| it's supposed to do. Also has excellent Windows[1] support so I
| can take it everywhere!
|
| [1]: https://github.com/LGUG2Z/komorebi/blob/master/justfile
| example justfile on my biggest and most active Windows project-
| might not seem like a lot but this has probably cumulatively
| saved me months of time
| guitarbill wrote:
| [flagged]
| bsnnkv wrote:
| > I get that your project is Windows-only, but many projects
| aren't.
|
| Nit: At this point you're better off starting a separate
| comment thread since you yourself already know that what you
| are about to talk about is not what my comment is talking
| about.
| guitarbill wrote:
| > Also has excellent Windows[1] support so I can take it
| everywhere!
|
| Nit: You mentioned it can be used "everywhere". That would
| be a useful feature! But while it's kinda true, there's
| some quite big limitations IMO
| 3eb7988a1663 wrote:
| The shell can be configured per OS. So, Windows can be set to
| use PowerShell and Linuxy systems will use sh.
|
| From the docs set windows-shell :=
| ["powershell.exe", "-NoLogo", "-Command"] hello:
| Write-Host "Hello, world!"
|
| Few things work seamlessly across platforms, and that does
| not seem like a huge burden.
| squeaky-clean wrote:
| > Wait, by "has excellent Windows support" you mean you have
| to set it to use Powershell or hope `sh` is installed on
|
| I don't get what the problem is here? Do you protest against
| shebangs too? Why does a build script for a Windows only app
| need to use sh instead of powershell? I think you're
| interpreting "excellent windows support" to mean cross
| platform, and that's not what it means.
|
| > So not only do you need just installed, which is yet
| another dependency,
|
| Yeah if you want to use some software, your computer needs
| that software. That's not a dependency. So we're talking zero
| dependencies, or one of you absolutely need sh.
| burnished wrote:
| To be fair it is another dependency for the project that
| you are using just with. Its probably not software that you
| use for its own sake.
| MatmaRex wrote:
| You can keep your commands simple enough so that they can be
| executed by both `sh` and `cmd.exe`. If you need anything
| more complex than invoking other programs, `&&`, `|` and `>`,
| it's time to rewrite your build script in a real programming
| language anyway.
| BeetleB wrote:
| You can use the usual cmd (I do). You're not limited to
| Powershell. Also, you do understand that if a tool has first
| class support for Windows, that does mean it prioritizes
| Windows tools, right? Imagine I made a command runner, and
| said it has "excellent Linux support", and then someone comes
| along and complains that you have to install Powershell on
| Linux to use Windows recipes.
|
| You can have Windows only recipes and Linux only recipes.
|
| Furthermore, if you have bash installed on Windows (e.g. via
| git bash), you can put a shebang in your recipes to use bash.
|
| We develop in Windows and deploy in Linux. Most of our
| recipes work in both OS's - either we use bash or Python for
| the recipe. The few that don't - we just mark as Windows only
| or Linux only so they're not available in the wrong OS.
|
| > So not only do you need just installed, which is yet
| another dependency,
|
| You do realize that Windows by default comes with almost _no_
| development tools, right? So yes, you do actually need to
| install things to get work done. The horror.
|
| I'll also note that while you complain about just, _you
| provide no alternative_.
|
| Weirdest rant ever.
| gurgeous wrote:
| We love just and are using it in all projects now. So great. Our
| typical justfile has around ~20 rules. Here is an example rule
| (and helper) to illustrate how we use it in ci:
| export PATH := justfile_directory() + "/node_modules/.bin:" +
| env_var('PATH') ci: @just banner yarn install
| yarn install @just banner tsc tsc --noEmit
| @just banner lint eslint src prettier --check src
| @just banner vitest vitest --run @just banner
| done! banner *ARGS: @printf '\e[42;37;1m[%s]
| %-72s \e[m\n' "$(date +%H:%M:%S)" "{{ARGS}}"
|
| This example is a bit contrived, more typically we would have a
| rule like "just lint" and you might call it from "just ci".
|
| One of the best features is that just always runs from the
| project root directory. Little things like that add up after
| you've spent years wrestling with bash scripts.
| alsetmusic wrote:
| > Little things like that add up after you've spent years
| wrestling with bash scripts.
|
| Can you please explain what you mean here? I looked at the
| GitHub examples and wondered why this would be preferable to
| Bash aliases and functions. I must be missing something.
| ricardobeat wrote:
| Bash has a thousand pitfalls, and as you accumulate layers of
| scripting they start compounding. Little things like "what
| the hell directory is this command actually running from",
| parsing input parameters, quoting rules, exit statuses,
| pipelining, etc.
|
| Tools like _just_ provide a very consistent and simple base
| to start with, and you can always still call a separate
| script, or drop directly into inline shell scripting.
| brundolf wrote:
| So it's not a fundamentally different use-case, it's just
| an admission that shell scripts suck at what they do?
| pdimitar wrote:
| Of course. Is that news to you? Not a snark, I am
| genuinely surprised, assuming that you asked seriously.
|
| I moved to ZSH some years ago but even that is not good
| enough. I thought of using Fish at one point but just
| said "frak this" and started writing Golang for anything
| that's more than 20-30 lines of bash/zsh scripting. Or
| requires their weird list / array syntaxes for iterating
| over stuff. Can't ever remember that with a gun to my
| head.
| udev4096 wrote:
| Shell scripts can be used safely if you know how to. Have
| solid error handling, exit on error (set -e), write tests
| (BATS) and a few other things to make sure it doesn't
| break. You are not gonna get the same performance with
| just or whatever new tooling there is just to run
| commands on your system
| pdimitar wrote:
| > _Shell scripts can be used safely if you know how to_
|
| That's the contention point though -- I learned and
| relearned shell scripting no less than 7 separate times
| and it always slips away because it's not something I
| practice every day. Ultimately I concluded it's not worth
| it because you mostly have to memorize super weird syntax
| and strange exceptions to rules. At one point I was just
| like "screw this" and went for Golang.
|
| > _You are not gonna get the same performance with just
| or whatever new tooling there is just to run commands on
| your system_
|
| That's very debatable, I'd bet my Go programs process
| various things either faster or with the same speed. But
| even if they are slower that's often not important
| because most scripts I ever wrote were throwaway. Those
| that stuck around I have polished and re-polished,
| including with the measures you enumerated.
| ricardobeat wrote:
| > if you know how to
|
| That's a _big_ if. I worked on a shell based tool for a
| couple years and eventually accumulated the know-how and
| toolset to write reliable code; but nobody else could
| contribute as the learning curve was too great.
|
| I switched to Ruby for all new tools and never looked
| back. Performance is rarely a concern in this territory,
| and you can always offload heavy work to another process.
| nightowl_games wrote:
| Performance in your shell script is a new one. Can you
| cite a real world example where that would ever matter?
| My shell scripts just initiate build/export/deploy
| programs. They take milliseconds to run and then the
| programs they start take minutes. The perf of those
| milliseconds couldn't be more negligible.
| 3eb7988a1663 wrote:
| For me, the niceties are in the built in functions[0].
| Commands to manipulate paths(!!), get cpu counts, mess with
| environment variables, string processing, hashing, etc. All
| the gyrations a more sophisticated script is going to
| eventually require. Instead of having to hack on it in shell,
| you get cross-platform utilities which are not going to blow
| up because of something as wild as a space or quote mark.
|
| [0] https://just.systems/man/en/functions.html
| richie_adler wrote:
| My favorite feature is the ability to decorate the recipe
| name with the OS and then write relevant code for each
| recipe that does the same in each OS.
| alsetmusic wrote:
| This best explains what I must be missing. Saying, "shell
| scripts are bad," doesn't tell me anything. Thanks for
| giving me a concept to explore. I'll have another look with
| this in mind.
| udev4096 wrote:
| Nah. This looks nothing more than a wrapper for bash
| scripts. I can easily write helper scripts which does
| exactly what you described above. I don't understand the
| need of using a whole different tooling when I can run
| scripts natively on my machine(s)
| nightowl_games wrote:
| Bash scripts need wrappers because they suck so hard.
|
| You can do it all in bash, yes, but it's very conceivable
| this "just" thing actually provides real value.
| gcmeplz wrote:
| I love the look of `just` and have been meaning to try it out,
| but this feels like one of those examples where Make's
| dependency management shines--it lets you specify that many of
| these commands only need to run when particular files change:
| node_modules: package.json yarn.lock yarn install
| --pure-lockfile prettier: $(shell find src -type f
| -iname "\*.ts") prettier --check src
| ... ci: node_modules prettier eslint vitest
|
| And as time goes on, I always end up wanting to parallelize the
| commands that can be parallelized (citest, lint, eslint), so
| I'll turn `make ci` (or `just ci`) into its own little script.
| stock_toaster wrote:
| The banner readability could be slightly improved using
| constants[1] (and prefixing with _ to hide it from list
| output). # print all available commands by
| default default: @just --list ci:
| @just _banner yarn install yarn install @just
| _banner tsc tsc --noEmit @just _banner lint
| eslint src prettier --check src @just _banner
| vitest vitest --run @just _banner done!
| _banner *ARGS: @printf '{{BOLD + WHITE + BG_GREEN}}[%s]
| %-72s{{NORMAL}}\n' "$(date +%H:%M:%S)" "{{ARGS}}"
|
| [1]: https://just.systems/man/en/constants.html
| jensenbox wrote:
| I have been using this for months now - way easier than Taskfile.
|
| The parameter injection and passing to commands was the thing
| that converted me.
| jcalabro wrote:
| I've been using just at work and in personal projects for almost
| a year, and I like it a lot. In particular, its self
| documentation with `just --list` makes onboarding new folks easy.
| It's also just a nicer syntax than make.
| peterldowns wrote:
| Agreed. Is it that different than Make with `.PHONY` targets?
| Yes -- it is Designed To Do Exactly What It Does, And It Does
| It Well. That counts for something in my book.
|
| All my Justfiles start with this prelude to enable positional
| arguments, and a "default" target to print all the possible
| commands when you run `just` with no target name:
| # this setting will allow passing arguments through to tasks,
| see the docs here #
| https://just.systems/man/en/chapter_24.html#positional-
| arguments set positional-arguments # print
| all available commands by default default:
| @just --list
| jdxcode wrote:
| in mise you wouldn't need that preamble. `set positional-
| arguments` is just how it behaves normally and `mise run`
| doesn't just show available commands--it's also a selector UI
| peterldowns wrote:
| That's nice, but I don't have any interest in switching
| because Just does everything I want. I legitimately have
| zero feature requests regarding Just.
| mike-cardwell wrote:
| I don't have my work laptop to hand to compare, but I usually
| run "just" to get a list of commands and what they do, rather
| than "just --list". Hope that saves you 7 key presses going
| forwards.
| peterldowns wrote:
| Running `just` will invoke the first recipe, so you need to
| add one that invokes `just --list` for this to work -- see
| https://just.systems/man/en/listing-available-recipes.html
| and my sibling comment.
| fmbb wrote:
| That seems like the most useless pattern to take from make,
| especially when you name your tool "just".
|
| Just what?
| TeMPOraL wrote:
| > _Just what?_
|
| "Oh... come on! _Just..._ <waving hands angrily>"
|
| Pretty clear to me :).
| layer8 wrote:
| Just execute.
| Cthulhu_ wrote:
| The same applies to make without arguments though, make
| what? Grammar / word meaning aside, unknown / missing
| commands printing the help file or suggestions is a good
| pattern.
| IshKebab wrote:
| I think it's less grammatically ambiguous with make. It
| implicitly means "make <the project>". For most projects
| that's pretty well defined (and also grammatically
| correct since 'make' is a verb and 'just' is not).
|
| But even so it would have been a better design for `make`
| to list top level targets or something.
| lambda wrote:
| Yeah, I've been adding `just help` as an alias for `just
| --list` and making it the first recipe for this reason.
| mike-cardwell wrote:
| Hmm. Maybe the dev that set it up made the first recipe run
| `just --list`
| pdimitar wrote:
| Not as much as 7, you can just type `just -l`.
| konfekt wrote:
| Maybe worth reminding the self-documenting Makefile [0]
| discussed here.
|
| [0] https://news.ycombinator.com/item?id=30137254
| camgunz wrote:
| I've been using this for years; love it
| banku_brougham wrote:
| Total agree. It constrains the chaos in my projects, and its
| easy to refactor bits into more sustainable cicd, if or when
| that is ever needed.
|
| The self documenting aspect is what puts jt above a folder of
| shell scripts for me
| throwaway743950 wrote:
| I recently looked at various alternatives to make and landed on
| https://taskfile.dev/
|
| It handles dependencies and conditions well without needing to be
| a full blown bash expert.
| majkinetor wrote:
| I use Invoke-Build[1] everywhere and I highly recommend it. It's
| cross-platform, uses PowerShell so we have serious programming
| language in the background and is extremely simple yet powerful:
| dependencies, integrated help, good defaults for error handling
| and starting directory, vs code support, DOT charts of task
| dependencies, incremental task, persistent builds, parallel stuff
| etc. See example usage here [2]
|
| [1]: https://github.com/nightroman/Invoke-Build
|
| [2]: https://github.com/majkinetor/mm-docs
| no_circuit wrote:
| Task is in a similar problem space.
|
| Unlike Just which clearly states it is not a build system [1],
| Task can be told about expected files so tasks can be skipped to
| avoid unnecessary work [2]. So if your task is to build software,
| IMO make and the others like Task would be better.
|
| If your tasks only care about the success code from a process,
| and/or are a Rust fan instead of Go, then Just should be fine.
| Otherwise, for specific use-cases like CI, you are likely already
| coding in a proprietary YAML/JSON/XML format.
|
| [1]
| https://github.com/casey/just/blob/e1b85d9d0bc160c1ac8ca3bca...
|
| [2] https://taskfile.dev/usage/#prevent-unnecessary-work
| jensenbox wrote:
| The one thing that converted us from Taskfile to Justfile is
| how it handle parameters injected at instantiation.
|
| https://just.systems/man/en/recipe-parameters.html just works
| better for us than https://taskfile.dev/usage/#forwarding-cli-
| arguments-to-comm...
|
| We use Docker Compose for our dev environment and were trying
| to do something like (notice the extra dash dash for separating
| the arguments out): task poetry -- add
| requests django
|
| It was not working as we expected for some of the users due to
| the argument dash dash stuff - they were forgetting due to
| muscle memory but the following does: just
| poetry add requests django
|
| under the hood it was just calling (the equivalent):
| docker compose run --rm --build poetry poetry "$@"
|
| Just arguments are more ergonomic.
|
| This is how just does it: poetry +command:
| docker compose run --rm --build poetry poetry {{command}}
| lormayna wrote:
| I agree with you: I automate many K8S command with task but
| everytime I forget about the - -
|
| Having a better input system will be a great improvement from
| usability perspective
| trallnag wrote:
| Currently, every few months, I switch between Task and Just.
| Started with Task, went to Just, now I'm using Task again.
| Procrastination at its best
| andreynering wrote:
| Task creator here.
|
| How do you evaluate each tool? What do you miss on each that
| keeps you switching between them?
|
| I understand you, though. I keep switching between Firefox
| and Chrome-based browsers because each has its pros and
| cons...
| hahn-kev wrote:
| Passing parameters kinda sucks, someone else made a
| comparison in another thread about named parameters and how
| easy it is to pass and define them in Just. Love taskfile
| otherwise
| lormayna wrote:
| Input parameter with - - is not really intuitive. It works,
| but the just way to handle input parameters is way more
| easier to remember
| DrRobinson wrote:
| Personally I disagree, I think `--` is very intuitive.
|
| Maybe it isn't super common knowledge, but `--` is in
| line with the POSIX argument parsing convention[0] and is
| used by many (most?) GNU/BSD tools and many other tools
| such as `kubectl`. This StackOverflow thread[1] also has
| some information about it.
|
| [0] https://www.gnu.org/software/libc/manual/html_node/Ar
| gument-...
|
| [1] https://unix.stackexchange.com/questions/11376/what-
| does-dou...
| LinXitoW wrote:
| I unironically like the YAML format. It's very readable, imho,
| and most people (at least in the web space) already know it.
| It's better than the way just does attributes and descriptions.
|
| On the other hand, what irks me is how parameters are fiddly to
| pass along. You have to define environment variables, instead
| of jusst passing them directly in the call.
| brokegrammer wrote:
| I switched from make a while ago because I was using it to run
| tasks in my Python projects, which doesn't require any of make's
| build tools.
|
| I didn't like make's complicated syntax either. Everything just
| makes more sense now.
| jascha_eng wrote:
| We recently switched pgai over to just. And are quite happy so
| far. The hierarchical nature is quite nice:
| https://github.com/timescale/pgai
| Traubenfuchs wrote:
| Why use this over .sh files?
| petesergeant wrote:
| Why use .sh files over this?
| al_borland wrote:
| Fewer tools to manage. It seems like this could also be
| replaced by some aliases in a .bashrc file.
|
| I don't like adding extra dependencies and complicating
| things if they aren't adding significant benefit. What am I
| missing here? It seems like an alias with extra steps.
| xigoi wrote:
| Because they don't require installing a new tool and learning
| new syntax.
| homebrewer wrote:
| When this tool becomes as available out of the box as POSIX
| sh (i.e. practically everywhere, including embedded systems
| and containers), then this reversed argument will make some
| sense. I'm willing to bet anything that POSIX sh will still
| be with us 50+ years from now, and 'just' will be long
| forgotten by then. You really should have a stronger argument
| for introducing another dependency into your build process
| (and onto your developers) than "it has a slightly simpler
| syntax compared to the industry standard".
| bigstrat2003 wrote:
| It's not "slightly simpler", it's _massively_ simpler.
| Shell scripts are pretty much the worst syntax in existence
| (barring esolangs that go out of their way to be weird).
| Hackbraten wrote:
| While shell syntax may be quirky, it absolutely allows
| you to write scripts that are simple, easy to understand,
| and maintainable.
| BeetleB wrote:
| It's great that POSIX sh is available everywhere except
| where it isn't (Windows).
|
| In all SW teams I've been in except one, sh was available,
| and people preferred writing things in something else
| (usually Python/Perl). I have had an order of magnitude
| more success convincing teammates to use just than
| convincing them to use sh.
|
| It may be ubiquitous, but it's useless if you can't
| convince non-shell gurus to use it.
| Fluorescence wrote:
| IMHO you'd right to be sceptical because for me, it is only a
| slightly more ergonomic way to organise and run shell scripts.
| It's difficult to make the case it's much better but I found it
| interesting how "just being a bit nicer" for a common activity
| can be a really valuable quality of life improvement.
|
| - easier - core benefit is making it nicer to implement
| multiple commands with arguments without inventing something
| equivalent in shell
|
| - convenient - with "fallback" just will search up the folder
| tree to find the just command so I don't need to be in the
| right folder. I have justfiles at multiple levels in a project
| hierarchy and my cwd works as context to pick the right command
|
| - polyglot - can use different languages as needed
|
| - predictable - it's so nice when I return to a project and I
| have recipes for setting up my env, various types of build and
| test. The consequence of being a little more ergonomic means I
| capture more useful command lines that, for whatever reason, I
| would not have made into shell scripts because of the added
| friction.
| e12e wrote:
| > with "fallback" just will search up the folder tree to find
| the just command
|
| So don't have just-files in your home directory?
| Fluorescence wrote:
| You could if you want.
|
| If you don't want just to search outside of your project
| folder then don't set fallback in your project root
| justfile and it stops there.
| IshKebab wrote:
| I don't know if this fixes the issues but some big problems
| with shell:
|
| * Very bad UX on Windows
|
| * Quoting is a disaster. I mean, the whole language is a
| disaster but quoting is an especially big wart. Make also has
| this issue; you literally can't use it with files containing
| things like spaces or colons.
|
| * Shell scripts tend to start simple and reasonable and grow
| seamlessly into something that absolutely should not be a shell
| script.
|
| My favourite solution is Deno. Zero faff to set up, easy to
| install, supports third party dependencies without metadata
| files or messing with environments, and you get to use a real
| programming language. Easily the best scripting tool for
| infrastructure tasks at the moment.
|
| Unfortunately I'm forced to use Python at work which is nowhere
| near as good as Deno, but still beats the pants off shell
| scripting.
| Hackbraten wrote:
| > Quoting is a disaster.
|
| It surprises me a bit that, of all things that are a mess in
| shell, your comment mentions quoting. It's one of the few
| things that absolutely make sense for me in shell scripting.
| Do you have an example for me where quoting feels messy to
| you?
|
| > My favourite solution is Deno. Easily the best scripting
| tool for infrastructure tasks at the moment.
|
| I don't think there's an objectively best technology for
| everyone. For example, how long-term are your infrastructure
| tasks? What are the chances your scripts are still going to
| work in 2 years? 5 years? 10 years?
|
| Suppose you're in a large enterprise embedded project which
| needs to work for 10 years or more, and the project uses
| shell scripts for infra tasks. Would you recommend to migrate
| those to Deno or Python?
| IshKebab wrote:
| Yes, this was literally from today:
|
| https://programming.dev/post/22539101
|
| Turn on shellcheck and you'll realise that nobody could get
| it right without tool assistance. In programming languages
| with "standard" quoting (Python, JavaScript, Rust, Go, C,
| etc.) you don't even really need to think about it.
|
| > What are the chances your scripts are still going to work
| in 2 years? 5 years? 10 years?
|
| 100% because I'll maintain them.
|
| > Suppose you're in a large enterprise embedded project
| which needs to work for 10 years or more, and the project
| uses shell scripts for infra tasks. Would you recommend to
| migrate those to Deno or Python?
|
| Absolutely yes. In fact the longer you expect it to last
| the stronger my recommendation would be. A shell script
| with 10 years of tech debt is a scary prospect.
| Hackbraten wrote:
| > 100% because I'll maintain them.
|
| What happens if you leave the project? Are your teammates
| going to maintain the scripts? What happens when one day,
| the Deno package gets updated and the script blows up?
| What if Deno becomes proprietary and closed source?
|
| > A shell script with 10 years of tech debt is a scary
| prospect.
|
| Several well-known executables on some Linux distros are
| really 20-year-old shell scripts. I haven't really seen
| them accumulate much tech debt.
| zahlman wrote:
| >of all things that are a mess in shell, your comment
| mentions quoting. It's one of the few things that
| absolutely make sense for me in shell scripting. Do you
| have an example for me where quoting feels messy to you?
|
| 1. The distinction that shell languages make between
| single-quotes and double quotes is unintuitive and not seen
| in other languages - wherein either they are
| interchangeable (like Python) or denote a completely
| separate type (like C and several others influenced by it).
|
| 2. I can't backslash-escape a single-quote within a single-
| quoted string. Single-quoting _disables_ backslash-escapes
| that were already working _outside of strings_. I 've lost
| count of the times I tried to input a command and was
| surprised to get a > continuation prompt because the shell
| thought I was still inside quotes, and then not had any
| good idea of how to fix my error on the previous line.
|
| 3. I _can_ use backslash escapes in a double-quoted string,
| but then I 'm also stuck with variable interpolations. It's
| difficult to produce a string that contains a literal
| double quote, literal dollar sign, literal at sign and
| literal double quote consecutively. Yes, by itself I can
| wrap that sequence in single quotes, but that doesn't
| generalize to contexts where I need more layers of quoting.
|
| 4. Really nothing generalizes very well to when you need
| multiple layers of quoting.
|
| 5. Not directly an issue with quoting, but there's implicit
| concatenation between quoted _and non-quoted_ tokens if
| there 's no space between the quote and the other part.
| This leads to many situations where you think you've gotten
| it right but you haven't, and don't notice until you either
| try to iterate on your script or carefully examine the
| output.
|
| 6. But you _have to rely on_ that confusing behaviour if
| you need a single-quoted string that contains a literal
| single quote.
|
| It's taken me quite a bit of practice to become able to do
| anything moderately complex, and I still have to check my
| notes sometimes. But really the underlying problem is that
| writing these things creates a demand to have some kind of
| internal structure within the string, so that parts of it
| can be further processed. It would be far nicer, for a
| start, if "interpolate values into the string" were an
| explicit operator rather than a magical property of double-
| quoted strings. But the main reason I end up using Python
| to orchestrate command-line tasks is just so I can have
| actual tuples or lists of strings and manipulate them on
| that level instead of at a textual level.
| bigstrat2003 wrote:
| Because shell is absolutely miserable to work with, whereas
| Just has decent syntax.
| olejorgenb wrote:
| I know the OP said ".sh files", but you can have executable
| python files (for instance as well)
| Astronaut3315 wrote:
| I've been happy with Just at our workplace. It lets me focus more
| on the task at hand instead of Conan / Cmake incantations.
|
| It's consistent, easy to use and maintain, and keeps all relevant
| operations in one place.
| __MatrixMan__ wrote:
| I'm not a fan. It works well for what it is, but what it is is an
| additional language to know in a place where you probably already
| have one lying around.
|
| Also, like make, it encourages an imperative mode for project
| tooling and I think we should distance ourselves from that a bit
| further. It's nice that everybody is on the same page about which
| verbs are available, but those verbs likely change filesystem
| state among your .gitignored files. And since they're starting
| from an unknown state you end up with each Just command prefixed
| by other commands which prepare to run the actual command, so now
| you're sort of freestyling a package manager around each command
| in an ad-hoc way when maybe it's automation that deserves to be
| handled without depending on unspecified state in the project
| dir.
|
| None of this is Just's fault. This is people using Just poorly.
| But I do think it (and make) sort of place you on a slippery
| slope. Wherever possible I'd prefer to reframe whatever needs
| doing as a build and use something like nix which is less
| friendly up front, but less surprising later on because you know
| you're not depending on the outputs of some command that was run
| once and forgotten about--suddenly a problem because the new guy
| can't get it to work and nobody else remembers why it works on
| theirs.
| nerdponx wrote:
| I mainly don't understand how Just is any better than a run/
| directory full of executable shell scripts.
| zwerdlds wrote:
| That works too. I've done both and I currently use Just
| because it collects the entrypoints to the project into a
| single file. This can provide an advantage where there's a
| bit of interdependence across your entrypoints.
|
| E.g: You have a docker container, you might be `run`ning it,
| `exec`ing it etc. from the same compose-file. So Just gives
| you the ability to link those shared commands within the same
| file. Once the entrypoints get too numerous you can either
| break them into scripts (I do this partially depending on the
| level of behavioral complexity in the script) or partition
| your justfiles and import them into a single master.
| pdimitar wrote:
| If that works well for you, use it.
|
| I did that for 10+ years and got fed up with having to
| remember which names I gave to my scripts that month. I
| gradually evolved my views and that got reflected with the
| names of the scripts.
|
| `just` helped me finally move away from that. Now I have i.e.
| `just check` in projects in different languages that all do
| the same thing -- check types and/or run various linters. I
| can go in a directory and run `just check` and I know I have
| taken care to have all checks that I want in place. Similarly
| I can run `just test` and I know I'll have the test suite
| ran, again regardless of the programming language or
| framework.
|
| Absolutely nothing wrong with a directory full of scripts but
| I lost patience for having to scan what each does and moved
| away from them.
| lijok wrote:
| > Now I have i.e. `just check` in projects in different
| languages that all do the same thing -- check types and/or
| run various linters. I can go in a directory and run `just
| check` and I know I have taken care to have all checks that
| I want in place. Similarly I can run `just test` and I know
| I'll have the test suite ran, again regardless of the
| programming language or framework.
|
| How is that different from having a scripts dir, and a
| script called `check` or `test`?
|
| How is `just -l` different to `ls scripts`?
| pdimitar wrote:
| I believe I already addressed that this is purely a
| matter of taste and convenience, not sure why you are not
| reading my comment and are asking for more.
|
| And it was already said: if you like it more, use it.
| Nobody is holding a gun to your head. And I even
| explained that I used that in the past and moved away
| from it.
| akoboldfrying wrote:
| I also haven't seen in your previous response how Just is
| better than a subdir with shell scripts _named according
| to a convention_.
|
| AFAICT, the productivity improvements you described came
| exclusively from using a consistent naming convention,
| not from Just. And since everyone's dev env supports
| subdirectories with shell scripts already, why not simply
| use that instead of requiring Just?
| pdimitar wrote:
| I got a down arrow on my comment that's your parent a
| minute before you responded. Coincidence, or you prefer
| to press it because you are not satisfied that I'm not
| your personal documentation agent?
|
| Finally and additionally as a response: because it's also
| all in one place. I don't want 10+ scripts. For the third
| time: I used bespoke scripts and found them not good
| enough compared to Just, now for even more reasons
| clearly spelled out. Sigh.
| akoboldfrying wrote:
| I didn't downvote you, though I found your answer
| unhelpful. (I've now _received_ 2 downvotes.)
|
| 10+ scripts with standard names ("clean", "test",
| "build", etc.) in a subdir added to $PATH seems to me to
| be easier to manage -- if the scripts are independent of
| each other. If they do have dependencies on each other,
| but the dependencies are "treelike" (meaning that for
| every target you might want to run, all of its transitive
| deps are reached via a unique path), it's still easier
| (than _either_ make or Just) to have separate scripts,
| and turn each dep into a plain invocation at the top of
| each script. It 's only when that approach starts to
| invoke deps multiple times (because it has become non-
| treelike) that either make or Just starts to offer an
| advantage.
|
| I think if you look at this with clear eyes, you'll see
| that 100% of the value you feel you're getting from Just
| is actually coming from the naming convention that Just
| nudged you towards.
| pdimitar wrote:
| Apologies for assuming you downvoted me then. :)
|
| And I have not touched your comment btw. I rarely
| downvote these days and I have to be really pissed to do
| so. I was not pissed earlier, more like a little
| frustrated as you seemed to ask without reading, as if
| demanding a complete answer without willing to piece
| together the info given in several other comments.
|
| So... you were talking about global scripts. I was not. I
| was talking about per-project directory with scripts
| because very often projects have their little quirks that
| make all their scripts frustratingly 99% identical but
| never 100%. I danced this tango dozens of times -- not
| exaggerating, I am a contractor (though I hope to finally
| stop, currently looking for a proper long-term job with
| good culture fit) and worked on many projects -- and
| ultimately got extremely frustrated.
|
| At one point I did attempt to make those universal
| scripts you speak of. The even more maddening thing is
| that they worked for part of the projects... and didn't
| work for others. It was a rough 60/40 split. So you end
| up maintaining even more of them. So I gave up.
|
| Very soon before that I found `just` and very quickly
| recognized the benefits: project-local commands /
| scripts, centralized location (just one file), ability to
| delegate to parent Justfile (i.e. you can have a
| dedicated folder for Golang projects and that one can
| contain a Justfile with e.g. `just lint` task that calls
| `go vet` and `staticcheck` etc., without having to copy-
| paste that into every Golang project Justfile file,
| though I actually prefer that nowadays -- better to have
| completely self-contained tooling after all but still,
| for super dev-specific stuff that does not belong in
| version control the parent Justfile workflow is quite a
| good fit), and a very easy syntax that still allows for
| doing stuff that will make you pull your hair out if you
| attempt them with pure sh or bash and if you haven't
| memorized their specifics over the course of a lifetime
| (which is something I attempted but gave up on because it
| was more or less memorization of exceptions of the
| exceptions).
|
| Now, to address this:
|
| > _I also haven 't seen in your previous response how
| Just is better than a subdir with shell scripts named
| according to a convention._
|
| I am not impressed by conventions that are not enforced
| with a spiked club. Which means: we the people forget
| stuff easily. I suffered from that too. Conventions don't
| mean much when you misspell the script filename or put
| `-f` instead of `-e` in the `set` call at the top of the
| script. :)
|
| I prefer loud failures and not silent mess-ups.
|
| My position is informed by a lot of negative past
| experiences. Does not mean that my priorities are
| universal or unconditionally better. Not at all. It means
| that everything I got through in my career made me
| appreciate `just` and it was a near-perfect fit for my
| needs.
|
| > _I think if you look at this with clear eyes, you 'll
| see that 100% of the value you feel you're getting from
| Just is actually coming from the naming convention that
| Just nudged you towards._
|
| Sure, it encouraged me to finally settle on a naming
| convention but I've done this before as well. I still
| prefer the singular file approach + ability to delegate
| to parent files.
|
| The less files in total the better. I have found this
| rule to make me more productive.
|
| If you have gotten this far: nowhere did I claim
| objective improvements. I had discussions in the past
| (might have been in other `just` threads even!) with
| curmudgeons who loudly proclaimed "skill issue!" on my
| non-preference towards make's bash-isms and weird rules.
| So for them `make` + other scripts (even Perl / Python
| ones) are working just fine and the rest are "kids
| running after shiny toys".
|
| I don't mind them thinking that. I have my motivation
| and, as said above, it's well-motivated given my past and
| my way of work and mental preferences.
|
| Hope that helps.
| akoboldfrying wrote:
| Thanks for going into more depth. I wasn't aware that
| Just could delegate like that, which does sound useful.
| And I certainly agree that bash and make are absolutely
| Byzantine at this point -- footguns on footguns. There's
| much value in using a tool that is powerful enough to do
| what you need, but not much more -- since that makes it
| much easier to reason about what a given
| instance/invocation of that tool could possibly be doing,
| without spending hours (years?) down in the detail.
|
| And it sounds like Just is that tool for you! I'll
| probably keep using make, now that I've spent so much
| time wrestling with its many idiosyncrasies, but you
| never know.
| pdimitar wrote:
| Thanks for productive response. <3
|
| > _And I certainly agree that bash and make are
| absolutely Byzantine at this point -- footguns on
| footguns._
|
| Yeah, that's my problem. Not like I don't have memory in
| my brain, not like I can't learn make and bash -- I did
| so several times almost from scratch but as I am not
| using them every day, the memories always fade. It's best
| to relearn something without footguns than one with.
| Hence I am using `just`. It's straightforward and very
| easy to catch up with even if you forget it. Not so with
| make and bash.
|
| If you are very invested in them and are feeling at home
| with them, great for you -- I am not claiming
| unquestionable and countless benefits. I am claiming it
| works well for my brain and my workflow, and most of all
| -- the frequency with which I have to do scripting.
| darrenf wrote:
| I like having individual files too as they can be
| independently managed by source control, linted, etc. And
| I've certainly been known to have a Makefile that's
| simply: all: @ls -1 tasks
| % :: tasks/% @./$<
|
| And then fill my `tasks/` directory with individual
| executables.
| qup wrote:
| Just so you can tend to your fragility around downvotes--
| you cannot downvote a reply to your own comment.
|
| So he isn't the culprit.
| pdimitar wrote:
| I tried my best to get the discussion back on topic and
| off-topic low-effort replies like yours don't help.
|
| Oh and I did not downvote him.
| kstrauser wrote:
| Tab completion. `just -l<tab>` shows all the commands and
| their descriptions.
|
| Aside from that, it has lots of built-in ergonomics like
| consistent argument parsing, functions to say what OS
| you're on, an easy way to hide helper functions, the
| ability to execute a justfile in a great-grandparent
| directory, etc.
|
| You can totally do any of those things with shell
| scripts. I prefer letting someone else invent all the
| bells and whistles there so I don't have to.
| brabel wrote:
| I am a bit confused. If you have your scripts in
| `scripts/`, doing `scripts/TAB` will also auto-complete!
| The other things seem like really minor benefits to me,
| not trying to say you should also feel the same, just
| giving my opinion.
| pdimitar wrote:
| In my case I prefer all these utility scripts to be in
| one file because 90% of them are 1-2 lines anyway. Zero
| point dedicating a directory with several 5-line files.
| kstrauser wrote:
| Scripts/tab won't show you the documentation of each
| script explaining what it's for.
|
| My genuine advice is to download it and play with it for
| an hour. If you don't like it, you've learned a little
| about a tool you're bound to come across sometime. If you
| do like it, now you've added another tool to your
| palette. Either way you learn something useful.
| raffraffraff wrote:
| I use "make", so I get most of this. But the one thing I
| would like is a sibling / parent / grandparent directory
| with ease, so I might switch.
| kstrauser wrote:
| I've used make for many things over the years. I'm
| competent with it. Make is such a breath of fresh air for
| the uses that don't involve actually incrementally
| building software. It's sooo less verbose. It's hard to
| describe the feel of a thing, but imagine learning to
| program with Java and then finding Python. If you're
| building a giant app developed by thousands of people,
| maybe Java's complexity starts to show a benefit. If you
| just want to quickly script something up, Python gets the
| job done with a tenth the boilerplate.
|
| There's room for both. Neither replaces the other. But it
| turns out many of my projects need tools closer to
| Python/Just than Java/Make.
| yencabulator wrote:
| > Tab completion.
|
| `./scripts/<tab>`
|
| `./sc<tab><tab>`
| banku_brougham wrote:
| yep just has good ergonomics for little things in my dev
| workflow
| BeetleB wrote:
| Well, for one, your recipes can be in another language (e.g.
| Python).
|
| You can build complex recipes out of simpler ones. Sure, you
| could do that by creating a new shell script that calls other
| shell scripts, but then you're reinventing just.
|
| You don't need to be in the directory to run those scripts.
|
| I think a better question for you: What's the benefit of
| putting .PHONY recipes in Makefiles, when you could just have
| a directory full of shell scripts. If you find yourself using
| .PHONY recipes, then you already have a reason to use just.
| e12e wrote:
| > Well, for one, your recipes can be in another language
| (e.g. Python).
|
| Surely this is true for stuff in a ./bin or ./scripts
| folder - binaries, python with shebang etc?
| e12e wrote:
| Ah, I see there's:
|
| https://just.systems/man/en/shebang-recipes.html
|
| Which could be done in shell, but typically rather be
| limited to oneliners (invoking awk) rather than piping a
| heredoc to an interpreter.
| akoboldfrying wrote:
| > You don't need to be in the directory to run those
| scripts.
|
| There's already an easy way to solve this: $PATH.
|
| > I think a better question for you: What's the benefit of
| putting .PHONY recipes in Makefiles, when you could just
| have a directory full of shell scripts. If you find
| yourself using .PHONY recipes, then you already have a
| reason to use just.
|
| Well, I think it's the same question, rather than a better
| question. And the answer is yes, if _all_ you need from
| make, now and in the future, is a set of .PHONY targets,
| then by all means just use shell scripts. make is used
| because often you need slightly more than this -- or you
| may do so tomorrow, and don 't want to change the syntax
| you use to accomplish tasks.
| BeetleB wrote:
| > There's already an easy way to solve this: $PATH.
|
| I have 10 projects. Each with their own set of shell
| scripts. You want me (and all other developers) to
| pollute the $PATH with 10 directories?
|
| And then you have a namespace problem. I usually have a
| "test" recipe in my justfiles. The analog would be a
| test.sh file. But with your solution, it will have to be
| projA-test.sh and projB-test.sh.
|
| And if I dump them all into the $PATH, how do I quickly
| see the scripts relevant to a particular project?
| L3viathan wrote:
| You can put `./scripts` in your $PATH, if you want.
| kstrauser wrote:
| Absolutely do not do this. That's all well and good until
| you clone a repo that 'scripts/ls' =>
| install_ransomwhere().
| olejorgenb wrote:
| You could put `.$MY-SECRET` it `PATH` and selectively
| symlink this to vetted script directories
| olejorgenb wrote:
| You can put .scripts last in PATH (or first - whichever
| disallows scripts/ls to take precedence over /usr/bin/ls)
| BeetleB wrote:
| 1. This requires that all your projects use "scripts" as
| the directory name.
|
| 2. This works only if you just happen to be in the
| directory above scripts.
| nerdponx wrote:
| Direnv is a great tool for this FWIW.
| BeetleB wrote:
| Won't work in Windows.
|
| I think it really has to be emphasized: One of the great
| things about just is that it works in Windows with no
| hassles.
| akoboldfrying wrote:
| Are you sure it won't work?
|
| I ask because cmd.exe has DOSKEY, which is basically a
| very slightly souped up version of bash's alias. I think
| it wouldn't be hard to use DOSKEY to replace CD and PUSHD
| with macros that run some command to update %PATH% and
| then change directory as usual.
| BeetleB wrote:
| There's probably a tool that will work similarly in
| Windows. I was saying it merely because that's what the
| direnv Github page implies.
| nerdponx wrote:
| But won't all the scripts break?
| BeetleB wrote:
| Are you writing scripts that will break?
|
| just isn't something magical that will make scripts meant
| for Linux work in Windows, you know. Some people do
| actual development in Windows and have Windows scripts.
| akoboldfrying wrote:
| I tend to work on different projects in different
| terminal sessions so I don't find this a problem, but OK,
| I can see the benefit of making the tasks a command line
| executes dependent on the current directory. (There are
| tools that can auto-adjust $PATH for you like this, but
| that would be a weak argument against Just (unless you're
| using them already) since it would mean swapping Just for
| that-other-tool.)
|
| If you use git and don't need multiple "layers" of
| Justfiles (i.e., if you have all your scripts in a
| scripts folder at the top level of your repo), then in
| bash you can get what you want with:
| run(){ `git rev-parse --show-toplevel`/scripts/$*; }
|
| Now from any repo subdir, `run clean` will run a script
| named "clean" in the scripts folder at the top level.
| BeetleB wrote:
| Although I'm coming off as a strong just evangelist, I do
| want to point out that if someone already has a workflow
| with just scripts, it's totally OK to continue with that.
| Personally, I think using just is simpler for those who
| already don't have that workflow.
|
| Likewise, if you are using make as a command runner and
| already know make well enough - by all means continue! In
| my experience, though, someone who doesn't know make will
| be much more likely to learn just than make.
|
| I tend to sneak justfiles into the projects I work on.
| They usually don't have any good automation (no make,
| perhaps some scripts with a doc/md file explaining which
| script is for what). I sneak the justfile in the
| repository, and when it's mature, start showing teammates
| how I use it. They typically then switch to it. I don't
| think they would switch to it if it were a Makefile.
| brushfoot wrote:
| Agreed, particularly if you pipe to fzf.
|
| (For those who haven't used it, fzf is a fuzzy-searchable
| menu for the command line. You pipe lines of input to it, and
| it shows them in a menu. You start typing and it fuzzy
| searches the menu and selects the best match. Then you press
| Enter to pipe that out, or Tab for multi-select. It's
| fantastic.)
|
| I have convenience functions in my profile script that pipe
| different things to fzf...scripts, paths in the current
| directory to copy to the clipboard, etc. It's indispensable.
|
| Bonus: progressive enhancement. If someone doesn't have
| fzf/those convenience functions, it's just a directory with
| shell scripts, so they don't have to do anything special to
| use them.
| slightwinder wrote:
| It's a different approach, none is better or worse, people
| simply have preferences.
|
| And all other features aside, it seems to be able to call
| commands from any subdirectory in a project, which is
| actually nice compared with a normal shell. I mean, you can
| replicate this with some lines of shellscripting, but not
| everyone seems to maintain an elaborated $BIN of personal
| tools.
| bbkane wrote:
| I agree, but `Just` as an incremental improvement is a much
| easier sell to teams than asking them to think about their
| builds completely differently and rewrite everything to fit
| that.
|
| Offering a cave man a flashlight is probably more helpful than
| offering them a lightbulb and asking them to wire up the cave
| to power it :D
| __MatrixMan__ wrote:
| It is definitely a very fine incremental improvement over
| make. It's just incremental progress in a direction that I
| don't want to be headed.
| pdimitar wrote:
| 1. The language is extremely simple and is consistent.
|
| 2. I agree on having to move away from imperative and go for
| declarative (if the latter was what you had in mind) -- any
| ideas for a better tool that does that and is just as easy to
| learn?
|
| 3. RE: cobbling together stuff with and around `just` is
| relatively trivial to fix f.ex. I have my own `just` recipes to
| bring up the entire set of dev dependencies for the project at
| hand, and then to tear them down. It's a very small investment
| and you get a lot of ROI.
|
| 4. RE: Nix, nah, if that's your sales pitch for it and against
| `just` then I'll just strongly disagree. Nix is a mess, has
| confusing cutesy naming terminology, has a big learning curve
| and a terrible language. All of that would be fine, mind you,
| and I could muscle through it easily but the moment I received
| several cryptic error messages that absolutely did not tell me
| what I did wrong and I had to go to forums and get yelled at,
| is the moment I gave up. `just` is simply much easier and I am
| not worried about not having Nix-like environments for my
| projects. Docker + compose work very well for this.
|
| Finally, your point about an obscure single command that people
| forget about in the future applies to literally any and all
| task runners and dependency managers, Nix included. That's not
| a valid criticism towards `just` IMO.
| __MatrixMan__ wrote:
| 1. It's a fine language but I have all kinds of "works on my
| machine" problems with it because it has no associated
| dependency manager. Other languages solve this with lockfiles
| and such, and it's likely that you're already doing that with
| one of those same languages in the same project. So just...
| Use the main language for whatever it is.
|
| 2. No, nothing's so easy, but you can get more if you're
| willing to work for it, and I think the juice is worth the
| squeeze.
|
| 3. For runtime state, I find that using just as a wrapper
| around Tilt or docker-compose or k3d or whatever just hides
| the perfectly adequate interfaces that those tools have. The
| wrapper discourages deeper tinkering with those tools. It's
| not a particularly difficult layer of abstraction to pierce,
| but it doesn't buy you enough to justify having an additional
| layer at all.
|
| 4. In the case I'm thinking of, the whole team was working
| happily because they had used a Just recipe to download a
| file from a different repo, and then somebody removed the
| recipe, but everyone (except the new guy) had the file from
| months ago, which worked. Nix wouldn't have let us
| accidentally get into a broken state and not know it. It
| would have broken as soon as we removed the derivation for
| the necessary file. I sent him the file through slack and
| then he was able to work, and only discovered later how it
| got there on my machine. That kind of uncertainty leads to
| expensive problems eventually.
| pdimitar wrote:
| 1. I don't follow. I work with Elixir, Golang and Rust and
| I use their dependency managers just fine. F.ex. I have
| `just deps` that does `mix deps.get` in Elixir and `go get
| -u ./... && go mod tidy && go mod vendor` in Golang.
| Furthermore, `just` does not claim to do dependency
| management. So what do you mean here?
|
| 2. Sure but I am not paid for it. Nobody will look at me
| with admiration if I delay an important milestone with 2
| weeks (or, more likely, 2 years) to invent such a tool. :/
| So not sure I get you here either.
|
| 3. We're veering into bikeshedding here and I will not
| argue; use whatever interface works best for you. I
| personally love having `just up` / `just down` / `just
| start` / `just stop` for my development dependencies of any
| project project. No more one big shared Postgres instance
| that if I screw it up (and homebrew did that a number of
| times!) I'll have to dig through TimeMachine for DB
| backups. I wisened up eventually and started making
| scheduled exhaustive backups of each DB... and then said to
| myself "forget it" and just started using separate
| containers for each project. For my work I found wrapping
| the tools worth it for not having to remember their bespoke
| full command lines. I standardized my tasks and I can enter
| almost any directory and run the same `just ...` commands
| and get what I expect as a result. To me that's valuable.
| But again, use whatever is convenient for you. No argument
| from me.
|
| 4. I don't disagree here and I am kind of 50/50 because on
| the one hand this is failure of process + lack of proper
| dev/ops tooling (f.ex. deleting this or that should raise
| alarms i.e. every such repository should have CI that makes
| sure everything important stays in place). On the other
| hand if Nix or anything else spares you from having to
| install those guard rails then sure, then it's a good fit
| for you. For my work and hobbies Nix is a net negative and
| I gave it more than a fair chance and I had enough of
| opinionated diva-like tools whose message is "learn
| everything about me to love me, baby". No thanks. But
| that's just a single example. Again, if there are tools
| that spare you from screwing up something accidentally, I
| usually vote strongly in favor of them.
| __MatrixMan__ wrote:
| People like Just when they're the one who is writing the
| recipes, because those recipes implicitly depend on
| whatever they have installed at the time of writing so
| everything is easy, but then other people come to the
| project and it has a culture of "IDK I just use the Just
| recipe," except that recipe doesn't work unless you've
| been around since it was written and have all of the
| right versions of things. For instance I've got all these
| errors like:
|
| > This application uses version go1.20 of the source-
| processing packages but runs version go1.23 of 'go list'.
| It may fail to process source files that rely on newer
| language features. If so, rebuild the application using a
| newer version of Go.
|
| They don't seem to be hurting anything but I'm not really
| sure how to reason about them since somebody packaged the
| commands together but didn't specify anything about the
| environment. The Justfile entry tells me that it's
| running some script in $FOO_DOWNLOAD_DIR but I've got
| some sleuthing to do to figure out where that dir
| actually is and how its contents were populated and what
| it has to do with `go list`.
|
| This is of course bad practice, but Just is the rug under
| which it is hidden and made to look like good practice.
| It's good that Just doesn't claim to manage dependencies,
| since it doesn't, but this action could instead be a go
| program in which case go _would_ be handling those
| dependencies for me.
| pdimitar wrote:
| I don't disagree. Your example is a good demonstration
| why Nix -- or a much more thorough Justfile -- would be
| needed.
|
| In my case I also supply the `.tool-versions` file so
| that only mandates the other dev to have Just and asdf /
| mise (for installing exactly the right versions of
| tools).
|
| I also tried having full Dockerized development
| environment but that proved to be too much of a hassle.
|
| But yep, in your scenario it seems like the other guys
| did sloppy work. Sadly 99% of everything can be misused
| by people who don't practice their craft well.
|
| (EDIT: Golang programs should really be made to work with
| the latest version, all being said and done. Another
| example of sloppy work, if you don't mind me saying.)
| danieldk wrote:
| _Nix [...] and a terrible language_
|
| I never get this criticism. Nix is a pretty nice, small,
| functional programming language and lazy evaluation makes it
| really powerful (see e.g. using fixed-points for overlays). I
| wonder if this criticism comes from people who have never
| done any functional programming?
|
| When I first started with Nix six years ago, the language was
| one of the things I immediately liked a lot. What I didn't
| like was the lack of documentation for all the functions,
| hooks, etc. in _nixpkgs_ , though it certainly got better
| with time.
| pdimitar wrote:
| I did say I could learn it and I do FP for 8.5 years now.
| It's not that.
|
| It's the obscure error messages, mostly. And as you said,
| documentation even to this day leaves stuff to be desired,
| thought that might be better nowadays, no idea and I don't
| plan to revisit still.
| o11c wrote:
| > like make, it encourages an imperative mode for project
| tooling and I think we should distance ourselves from that a
| bit further.
|
| Um, what? `make` is arguably the most common declarative tool
| in existence ...
|
| Whenever people complain about Make in detail, it's almost
| always either because they're violating Paul's Rules of
| Makefiles or because they're actually complaining about
| autotools (or occasionally cmake).
| joshuamorton wrote:
| Make isn't, at all, declarative. It's almost entirely based
| on you writing out _what_ to invoke, as opposed to what
| should exist and having the build system "figure that out".
|
| That is, in make you say `$(CC) -c foo.c -o foo.o`, which is
| telling you, ultimately, how to compile the thing, while
| declarative build systems (bazel/nix/etc.) you say "this is a
| cc_binary" or "this is a cc_library" and you let it figure
| the rest out for you.
| GuB-42 wrote:
| If your executable is named "foo" and there is a "foo.c"
| somewhere, your Makefile only needs to contain "foo:" and
| make will figure out how to build it using its default
| rules. If you have more than one file (ex: foo.c and
| bar.c), just write "foo: bar.c".
|
| Modern build systems are more advanced and have better
| defaults, but the general idea is the same. They are all
| declarative. An imperative build system would be like a
| shell script.
| o11c wrote:
| Your "declarative" systems are no more declarative - they
| just _hide_ the commands /flags being used, far worse than
| `include config.make`.
| __MatrixMan__ wrote:
| It's quite easy to accidentally write makefiles that build
| something different when you run them a second time, or when
| some server that used to be reliable suddenly goes down. Or
| when the user upgrades something that you wouldn't think is
| related.
|
| It does no validation of inputs. So suppose you're bisecting
| your way towards the cause of a failure related to the
| compiler version. Ideally there would be a commit which
| changed the compiler version, so your bisect would find a
| nice neat boundary in version history where the problem
| began. Make, by contrast, is just picking up whatever it
| finds on the PATH and hoping for the best. So the best you
| can do is exclude the code as the source of the bug and start
| scratching your head about the environment.
|
| That willingness to just pick up whatever it finds and make
| changes wherever it wants with no regard to whether
| dependency created by these state changes is made explicit
| and transparent to the user is what I mean by "imperative".
| AlotOfReading wrote:
| I find declarative build systems end up pretty frustrating in
| practice. What I want from a build often _isn 't_ the
| artifacts, but the side effects of producing the artifacts like
| build output or compilation time. You get this "for free" from
| an imperative tool, but represents a significant feature in a
| declarative system that's usually implemented badly if it's
| implemented at all. The problem gets worse the smarter your
| tool is.
| thfuran wrote:
| >What I want from a build often isn't the artifacts, but the
| side effects of producing the artifacts like build output or
| compilation time
|
| You frequently build things not to get binaries but to spend
| time compiling?
| AlotOfReading wrote:
| The point is that there's often no way way to express "I
| want side effects" in declarative tools, and the number of
| side effects that might be useful is vast.
|
| For example, sometimes I profiling the build times to see
| where I should focus effort.
|
| Sometimes I want to see it to quickly check for issues
| where adding some dependency header causes build times to
| explode 100% in downstream dependencies during cold builds.
|
| Another common occurrence for is trying to debug a
| platform, toolchain, or standard library issue and the
| build system either doesn't detect changes in those
| components or only makes the components readily accessible
| in an internal cache that's subject to invalidation issues.
| You'll usually get the wrong artifact or test results in
| those cases.
|
| Some other systems (e.g. bazel/blaze comes to mind)
| actively try to hide side effects like stdout.
|
| In all of these cases, the only way to actually get these
| side effects is to reach into the tool's internals by
| blowing away caches/output folders or reading live log
| files. That's a failure of the build tool.
| MereInterest wrote:
| I haven't used it, but it sounds like make's ---assume-
| new flag does exactly what you want for the first part.
| It lets you rebuild everything that would result from a
| changed file, including all side effects, without needing
| to first update the file.
| AlotOfReading wrote:
| --always-make/-B is more in line, but yeah. Make has
| grown imperative models within its vast declarative
| morass.
| eru wrote:
| Alas, Make is really, really awful in most other
| respects.
| PittleyDunkin wrote:
| Really? It's the one part of the traditional c build
| system I actually still use. Easy to write, easy to
| debug, relatively small--what's the issue? I hear people
| complain about make incessantly but people rarely have
| substantial criticism to offer. Is it the syntax?
| Reliance on the filesystem? Inconsistencies between
| implementations?
| ajb wrote:
| As an actual builder it has limitations, such as not
| having (built in) the ability to know if it can still do
| an incremental build after changing some build option.
| That can result in inconsistent builds.
|
| The main problem is that you often require more logic
| than makes sense to write in make, but it kind of has a
| language built into it so people try to use it. But as a
| language it's terrible (no scoping, many missing
| features). So people end up implementing their build
| logic in a bastard combination of make and shell which is
| very opaque and difficult to debug.
|
| For example, I was recently trying to figure out how the
| OpenWRT makefiles are doing something, and it was really
| painful, because with make having no scoping any part of
| the system could end up affecting the piece you are
| looking at. There is a lot of dropping into shell to get
| stuff done, and a lot of the targets are themselves
| expanded variables, which makes it really opaque. Really
| a lot of it is not gaining from being written in make,
| they could do with rewriting large parts in a real
| language. But it would be a huge job. And that's where a
| lot of makefile systems end up
|
| That's why you get tools like ninja where they decided
| not to allow any logic at all.
| eru wrote:
| > That's why you get tools like ninja where they decided
| not to allow any logic at all.
|
| Or you get shake, where your logic is the logic of a real
| programming language.
| eru wrote:
| > Inconsistencies between implementations?
|
| That's actually not too much of a problem in practice:
| almost everyone just uses Gnu Make.
|
| > Easy to write, easy to debug [...]
|
| Alas, Make becomes hard to write and really hard to debug
| past a certain complexity threshold. And you reach that
| complexity threshold very quickly.
|
| > Is it the syntax?
|
| Yes, the syntax of Make is awful, and I'm not even
| talking about ergonomics. Thanks to Make's abysmal
| syntax, special characters in your files make it barf
| completely. And by 'special' I mean something as mundane
| as spaces.
|
| But everything you mentioned is far from the worst. See
| eg https://news.ycombinator.com/item?id=17088328 for a
| more comprehensive overview of Make's sins.
| hamandcheese wrote:
| Generally my aim with both Nix and Bazel are that, while
| they are the source of truth, day-to-day development and
| debugging occurs using language-native tools. So the only
| touch point for local development is when you are
| modifying the dependency graph in some way.
|
| It's definitely more work (you need to maintain
| compatibility with two different build systems), but
| worth it for exactly these reasons.
| eru wrote:
| > The point is that there's often no way way to express
| "I want side effects" in declarative tools, and the
| number of side effects that might be useful is vast.
|
| Shake (https://shakebuild.com/) is pretty good about
| letting you specify that a specific step produces
| multiple artifacts.
|
| I suspect Nix can do the same?
|
| > Some other systems (e.g. bazel/blaze comes to mind)
| actively try to hide side effects like stdout.
|
| Yes, blaze isn't all that great. You can tell, because
| Google folks check in generated artifacts into their
| repositories, instead of wrestling with getting blaze to
| build them.
| IshKebab wrote:
| So do you just not use incremental builds at all? That's
| insane.
| AlotOfReading wrote:
| Of course I do, but this isn't a thread about all the
| things that fit well in the paradigm.
| __MatrixMan__ wrote:
| Logs emitted during the build, or test results, or metrics
| captured during the build (such as how long it took)... these
| can all themselves be build outputs.
|
| I've got one where "deploying" means updating a few version
| strings and image reverences in a different repo. The "build"
| clones that repo and makes the changes in the necessary spots
| and makes a commit. Yes, the side effect I want is that the
| commit gets pushed--which requires my ssh key which is not a
| build input--but I sort of prefer doing that bit by hand.
| tucosan wrote:
| The developer time required to learn and properly use nix
| makes it unattractive to most teams. The benefits don't
| outweigh the costs of adoption.
|
| Instead of debugging code, the team would have to spend
| significant time maintaining the build system for the build
| systems sake. Don't get me wrong, I want something nix-like
| in my toolbox. I want to love nix. But I wouldn't dare to
| argue my team to commit to the world of pain that comes
| with it.
|
| There's a good reason that nix didn't see wide adoption in
| the industry.
| hamandcheese wrote:
| In my experience, Nix is very high leverage. My company
| has ~5 nix gurus, but Nix is invisibly used by hundreds
| of engineers. Most engineers know we use Nix and that's
| about it.
| smilliken wrote:
| Similar experience for me. In my company adopting nix
| paid off in weeks with no prior experience. Very happy
| with it almost 10 years later and at much larger scale.
| The difference between things working reliability or not
| is too big to overstate.
| brabel wrote:
| I tried using Nix but stopped for two very practical
| reasons: it's very slow and it's extremely disk heavy.
| Install a couple of things and suddenly your nix store
| weighs at 100 GB.
| danieldk wrote:
| Interesting. For me it's generally much faster than other
| package managers. The evaluation takes some time, but
| copying derivations from a cache to the Nix store is so
| much faster than traditional package management.
|
| I wonder if you somehow ended up eval'ing many versions
| of nixpkgs?
|
| _your nix store weighs at 100 GB_
|
| -\\_(tsu)_/- outside very constrained devices, who cares?
| I just checked my NixOS dev VM that I have used for
| months now and cannot remember when I last garbage
| collected. It's 188GiB, but I have many different
| versions of CUDA, Torch, etc. (the project I'm currently
| working on entails building some kernels for many
| different build configurations), and I run nixos-
| unstable, where a lot of stuff changes, so generations
| are pretty unique.
|
| A 2TB NVMe SSD is just over 100 Euro. Caring about 100GiB
| seems to be optimizing for the wrong things.
|
| I completely agree on embedded machines though. Just
| deploy it by copying the system closure, garbage
| collecting anything but the previous closure for backup,
| it'll be pretty much the same size as any other Linux
| system.
| brabel wrote:
| > For me it's generally much faster than other package
| managers.
|
| I don't know what kind of package manager you were using,
| but I've never seen an update take a good part of an hour
| before Nix.
|
| > outside very constrained devices, who cares?
|
| Seriously, are we going to shame people who can't afford
| to buy lots of storage?? My smaller laptop has only
| 250GB, but that's freaking plenty if I stick with apt.
| But I can barely run Nix on it.
| robinsonb5 wrote:
| > Seriously, are we going to shame people who can't
| afford to buy lots of storage??
|
| It's not just storage, though - storage may be cheap but
| once your machine is at capacity (the physical space in
| laptops is an important constraint) you have to replace
| perfectly good hardware to accommodate absurdly space-
| hungry software (looking at you, Vivado).
|
| Also, don't forget that not everyone has always-
| available, fast, reliable, cost-free internet. By rural
| standards my connection's very good, but 100gb would
| still tie it up for several hours, assuming I didn't need
| it for anything else in that time.
|
| Digital wastefulness is a problem, and I do think we need
| to take it more seriously.
| danieldk wrote:
| _but 100gb would still tie it up for several hours,
| assuming I didn 't need it for anything else in that
| time_
|
| Except that Nix does not download 100 GiB under unless
| you are installing a gazillion packages. First, Nix
| downloads compressed output paths. Second, it's not like
| Nix packages are substantially larger than Debian,
| Ubuntu, or Fedora packages. The extra storage space comes
| from (1) Nix keeping multiple generations to allow you to
| roll back to previous versions of the system -- if you
| break something, you can always roll back; (2) people
| using multiple different versions of nixpkgs, which could
| lead to having multiple versions of system libraries.
|
| (1) is a feature of Nix/NixOS, if you want to use less
| space, you can trade off the ability to roll back for
| space. You could always garbage collect everything except
| the current generation and it would be similar to other
| distributions. For (2), avoid using multiple nixpkgs
| versions.
|
| I generally like keeping around a lot of generations,
| etc. so I don't mind my history of NixOS systems keeping
| 100-200 GiB. But if you care about space, garbage collect
| and it won't take up that amount of space.
| robinsonb5 wrote:
| Thanks - I appreciate the background info.
| danieldk wrote:
| _I don 't know what kind of package manager you were
| using, but I've never seen an update take a good part of
| an hour before Nix._
|
| Pretty much all popular package managers. APT/dpkg,
| DNF/rpm, pacman, etc.
|
| I have just updated one machine to the latest unstable.
| It updated 333 packages, a substantial part of that
| system. It took 1 minute and 50 seconds, most of it
| downloading. So, not sure how it takes a good part of an
| hour for you.
|
| _Seriously, are we going to shame people who can 't
| afford to buy lots of storage??_
|
| I'm not shaming anyone. Just saying that 1 or 2 TB is
| pretty normal nowadays (outside Mac, because Apple makes
| you pay for it). At any rate, you can make the size
| pretty similar to any other distribution. It's not like
| glibc or GNOME takes up substantially more disk space on
| Nix.
|
| If you end up using 100 GiB of storage, you are either
| keeping a lot of system generations around _or_ you
| somehow have different nixpkgs versions in your system 's
| closure, ending up with duplicate versions of glibc, etc.
| If the former is the case, set up automatic garbage
| collection and the space use will be far less. E.g. on
| one machine I have only three NixOS unstable generations
| and the system is 18 GiB (which includes a bunch of
| machine learning models, etc.). It would probably be
| substantially less on NixOS stable, since there are less
| differences between generations (e.g. I have qemu,
| webkitgtk, etc. three times).
| nh2 wrote:
| Adding some data here:
|
| Total size of installation is roughly comparable between
| NixOS and, say, Ubuntu.
|
| My laptop's Nix closure of 1 generation is 33 GB. My
| desktop Ubuntu has 27 GB (20 GB /usr + 7 GB in /var,
| where snaps and flatpaks are stored).
|
| Indeed the disk usage of Nix comes from multiple
| generations. Every time there is a new version of glibc,
| gcc, or anything that "the world" depends on, it's
| another 33 GB download. Storing the old generation is
| entirely optional. The maximum disk space needed is 2
| generations.
|
| Updating Ubuntu to a new LTS version almost always costs
| me multiple hours, caused by interleaved questions on how
| to merge changed config files in /etc (which
| unfortunately one cannot seem to batch), apt installation
| being rather slow, and during recent years, the update
| generally breaking in some way that requires a major
| investigation (e.g. the updater itself dies, or
| afterwards I have no graphics). On NixOS, these problems
| do not exist, and the time to update is usually < 30
| minutes.
| dlahoda wrote:
| use only stable nix. override nixpkgs for inputs you add.
| after first build, use offline and no-substitute flags on
| reuse, alias such command. use nixdirenv.
|
| read and setup store/gc settings work for you. do not use
| nixenv nor nix profile.
| danieldk wrote:
| In my experience Nix is a force multiplier. But you need
| someone on the team who has plenty of Nix experience,
| because you inevitably need to write your own derivations
| and smoothen over issues that you might encounter in
| nixpkgs.
|
| We use Nix with Cachix in the team I currently work in.
| We use a lot of ML packages/kernels, which are nearly
| impossible to manage in Python venvs (long build times
| because we have to patch some dependencies, version
| incompatibilities, etc.). Now you can set up a
| development environment in seconds. The nicest thing is
| when we switch between branches we automatically have the
| state of the world needed for that branch (direnv yay).
|
| It was some work to set up, but it saves so much time
| now.
| letier wrote:
| How do you do the initial setup? I'm concerned with
| anything that happens before activating the dev shell.
|
| Right now I wrote a bash script to check for nix, direnv,
| git, gpg, etc. But it feels a bit clumsy, compared to the
| flake that contains the dev shell.
|
| For my own system I set up home manager. But I don't want
| to make the use of home manager a requirement, as it can
| be quite opinionated. (e.g. setting up direnv will be
| done by generating a .zshrc, which can be limiting to
| some)
| danieldk wrote:
| For our particular project you only need to install Nix
| and then run _nix develop_ , but I'd indeed recommend to
| use direnv. For me it's not an issue, since I run NixOS
| on development VMs, but a colleague who was not using Nix
| before (I think) also wrote a bash script to set up an
| AWS VM with the NixOS AMI and then rolls out a minimal
| NixOS configuration.
|
| I think for people who don't want to dive into Nix much,
| doing an imperative install (nix profile install) of the
| necessary packages is also fine. You could even make your
| own small meta-package that depends on everything that is
| needed. Then they could do a _nix profile install
| yourflake#yourmetapackage_ and have all the tools they
| need. But I agree direnv is a bit harder, since you 'll
| have to put something in the shell rc/profile.
| letier wrote:
| The imperative install is as many lines of code as the
| flake itself. That's what's bothering me. But a meta
| package would be a step in the right direction.
|
| Thank you!
| eru wrote:
| If you don't want to buy into the whole Nix philosophy, you can
| also use something like 'shake' (https://shakebuild.com/) to
| build your own buildsystem-like command line tooling.
| BiteCode_dev wrote:
| just is not meant as a built tool, just a task runner. Those
| have vastly different goals.
|
| make is a build system: it has targets, it has file deps, a dag
| resolver, etc.
|
| But a task runner is basically a fancy aliaser with task deps
| and arg parsing/proxing.
|
| And just is good at being that. Although I agree I not a fan of
| adding yet another DSL.
| zahlman wrote:
| Maybe because it's been many years since I used C or C++ for
| anything serious, but I don't get that impression from using
| make in the first place. I haven't seen it used for setting up
| a build environment per se, so there aren't any "packages" for
| it to manage. When I've written a Makefile, I saw it as
| describing the _structure of cache files_ used by the project
| 's build process. And it felt much more declarative than the
| actual code. At the leaves, you don't tell it to check file
| timestamps; you tell it which files' timestamps need to be up
| to date, and let it infer which timestamps need to be compared
| and what the results of those comparisons need to be in order
| to trigger a rule. Similarly, a rule feels composed of other
| rules, more than it feels implemented by invoking them.
| pdimitar wrote:
| I love `just` and have adopted it universally in all my projects.
| For what it does, it gets the job done fantastically.
|
| That being said, I found myself needing a tool that builds a DAG
| of dependent tasks and automatically figures out what can be ran
| in parallel and what cannot -- obviously you have to spell out
| all tasks and who depends on what first.
|
| Anybody knows such a tool?
|
| EDIT: Apparently people did not get the hint that I believe
| `make` is an over-engineered pile of metric tons of legacy and
| I'll sooner slash my wrists than to learn it in full.
|
| I did mean something ergonomic and easy to read and write. And no
| I'll never view `make` as such. I tried. Many times. I have
| better things to do in my life than to memorize exceptions of the
| exceptions.
| guipsp wrote:
| Make?
| pdimitar wrote:
| Come on, be serious. If I wanted ancient sh-isms and bash-
| isms I would have learned make to 100% some 15 years ago.
|
| I meant something ergonomic and easy to read and write.
| ofrzeta wrote:
| They are right, though, aren't they? I mean .. if you want
| something "modern", go ahead and learn Bazel. Make is quite
| a bit easier to learn, I'd say, and you don't need much
| (also no shell/bash) to express your DAG dependencies.
| pdimitar wrote:
| I'll agree on the DAG bit but I'll never use `make` again
| and I tried for no less than 10 years (on and off, not
| 24/7, otherwise I would have learned it long ago indeed).
|
| I stay away from `make` almost religiously. Its
| complications _always_ find a way to creep into your file
| one day. Always. :(
|
| So while they are technically correct and it's my fault
| for not saying I don't want `make` in the comment up-
| thread, I don't think my comment deserved the down arrows
| but oh well, I'll live through it.
| Izkata wrote:
| > If I wanted ancient sh-isms and bash-isms
|
| So don't, set make's shell to something else instead. It
| doesn't understand the recipes, it just dumps them to a
| file and runs $(SHELL) on them.
|
| For a more extreme example, just to show what's possible:
| SHELL := python3 .ONESHELL:
| foo.csv: import csv with open("$@", "w") as
| f: writer = csv.writer(f)
| writer.writerows([ ['Test1', 'Test2'],
| ['Test3', 'Test4'], ])
| pdimitar wrote:
| Not a bad idea, thanks. I did this a few times as well
| but when I analyzed the ROI I figured that just writing a
| simple-ish Golang program is just less confusing and more
| consistent in its totality when you ask yourself "do I
| really have to use Make and Python and, and, and...?".
|
| So yeah, thanks for bringing visibility to this pretty
| decent compromising approach. It worked for me for a
| while but eventually I just went all-in to either use
| `just`, some _very_ short bash/zsh scripts, or jump all
| the way to Golang.
| thechao wrote:
| I'm this years old when my life was revolutionized.
| plmpsu wrote:
| Maven, Gradle, etc.
| diggan wrote:
| Besides Make, I guess Bazel kind of fits the bill? It was very
| "Googly" last time I checked it out, but I think that was a
| decade ago and right when it was released, so it might be more
| fitting for not-Google nowadays.
| pdimitar wrote:
| I never looked at it but seen some fairly negative reviews
| here on HN. Any idea why? And why do you like it?
| kstrauser wrote:
| Imagine that instead of a make target listing its
| dependencies, you had to pull them out into a separately
| maintained BUILD file.
|
| That's not quite true, but it feels like it sometimes.
| Bazel is nice about seeing exactly what you need to rebuild
| if you touch a file. It's very, very complex though.
|
| In code terms, think of it as a framework that you have to
| embed your project into, not a Makefile or such that you'd
| drop into a project. That doesn't make it bad and it has
| its niceties. You've gotta be prepared to pay for them with
| sweat equity.
| pdimitar wrote:
| Thank you. I heard similar sentiments RE: complexity and
| that's usually enough to turn me off of a tool.
| bfLives wrote:
| I think this is exactly the intended use case for Ninja. It's
| discussed in this recently posted article.
|
| https://news.ycombinator.com/item?id=42268310
| pdimitar wrote:
| Thanks. That article is fairly disappointing for not having
| even one simple example file though...
| tjalfi wrote:
| Julia Evans has a Ninja introduction[0] with simple
| examples. I tried it for awhile, but ended up going back to
| GNU Make.
|
| [0] https://jvns.ca/blog/2020/10/26/ninja--a-simple-way-to-
| do-bu...
| pdimitar wrote:
| Just gave this a read. Impressive. I'll give ninja a try
| soon, I have a possible use-case for it. Thanks!
| aidos wrote:
| I've not tried it but this popped up on here a while back and
| sound like it might fit the bill.
|
| https://taskfile.dev/
| pdimitar wrote:
| Thanks, this one has been in my radar for a while, I'll
| absolutely get to it at one point.
| j6m8 wrote:
| I wrote frof [1] for exactly this purpose :)
|
| Designed to be ultra-simple and with minimal "config-file
| acrobatics".
|
| It looks like this [edit, formatting]: write
| -> analyze build -> analyze write:
| echo 1 2 3 > data.txt build: compile_tool.sh >
| tool.sh analyze: tool.sh data.txt
|
| https://github.com/j6k4m8/frof/
| pdimitar wrote:
| Can you explain that one a little bit more to me, please?
|
| I don't get the first two lines of your example well. They
| seem to show the dependency but which one is the default
| task, or how do you ask for a task to be ran?
| j6m8 wrote:
| You write the file and ALL steps are run in topological
| order so that a job never runs until its dependencies have
| run. i.e., in a tool I'll have `build.frof` as a separate
| frof file than `download-dependencies.frof`, perhaps. (If
| your preference is that those belong in the same file I'd
| be down to have PRs that support that! Should be very easy,
| I'm happy to try implementing this if there's interest.)
|
| So for a file with those contents called `mygraph.frof`,
| you can (after installing) run `frof mygraph.frof` to kick
| off the jobs in the current shell (inheriting env vars
| etc).
|
| [edit] maybe a clarifying example here:
| https://blog.jordan.matelsky.com/frof-render/
| pdimitar wrote:
| OK, so for the example in your comment upthread both
| `write` and `build` will be executed sequentially?
| j6m8 wrote:
| here they'll probably be executed simultaneously, since
| they both have zero dependencies and the machine can run
| multiple jobs at the same time. (can be disabled with
| `--max_jobs=1` or `-p=1`).
|
| Here's another illustrative example: A
| -> B B -> C Z -> C
|
| In this situation, frof will schedule `Z` to run in a
| parallel thread ASAP, so it will likely run alongside
| A... and if Z takes longer to run than A, Z will continue
| running when A stops and B starts. But C will wait for
| all other jobs to finish before it can schedule.
| pdimitar wrote:
| Nice, thanks a lot. Unfortunately I am quite swamped
| recently so I will definitely cannot help you with
| feature requests and testing but I have bookmarked frof
| and absolutely will be giving it a try.
|
| Just one thing I would dislike... Python. How easy it is
| to run frof without having to fiddle with venvs and such?
| j6m8 wrote:
| no worries, good to know this would be a useful feature!
| I'll add it to my backlog. pip install
| 'git+https://github.com/j6k4m8/frof/'
|
| and then frof myfile.frof
|
| should work!
|
| Was thinking about rewriting it in Go recently... :)
| pdimitar wrote:
| I'll try the vanilla Python route but knowing our mutual
| hatred, it'll crap the bed in 0.5s. :D We'll see.
|
| > _Was thinking about rewriting it in Go recently... :)_
|
| And then I might actually contribute. :)
| burnished wrote:
| I've found prototyping in python followed by a rewrite in
| Go quite pleasant, would recommend
| matja wrote:
| FYI to some people trivializing self-harm in a technical
| discussion is rather tasteless.
| pdimitar wrote:
| It's an exaggeration to illustrate a point. Still, thanks for
| bringing in the perspective.
| zahlman wrote:
| I disagree, fundamentally, that using a hyperbolic metaphor
| "trivializes" the underlying concept used.
|
| Regardless, I have found over the last several years that
| attempting to scold people for not measuring up to your
| standards - ones they never signed up to uphold - without a
| serious attempt to justify them is strongly
| counterproductive.
|
| Especially when it's couched in language that will readily be
| interpreted as snarky. One of the reasons people dislike the
| phrase "it's not my job to educate you" so much is that it
| takes for granted the presumption that the underlying idea is
| a subject of _education_ , i.e., an objective fact rather
| than an article of someone's worldview. Prefacing a claim
| with "FYI" (i.e., "for your information") has the same issue.
| Taste, in the metaphorical sense used here, is definitionally
| not objective, and thus it is not possible in principle to
| "inform" others of what is or is not in good taste - only of
| some other community's standards for taste.
| sgarland wrote:
| I love just. The main benefit for me at work is that it's much
| easier to convince others to use, unlike make.
|
| I like make just fine, and it's useful to learn, but it's also a
| very opaque language to someone who may not even have very much
| shell experience. I've frequently found Makefiles scattered
| around a repo - which do still work, to be clear - with no known
| ownership, the knowledge of their creation lost with the person
| who wrote them, and subsequently left.
| biztos wrote:
| I'm hoping for this effect, as more and more I work with people
| who don't consider `make` the default (or, more often, have
| never heard of it).
|
| But I think the hard part -- for any build system -- is
| achieving the ubiquity `make` had back in the day. You could
| "just" type "make" and you'd either build the project, or get
| fast feedback on how much that project cared about developers.
| soulofmischief wrote:
| Can anyone with experience with just and tools like npm/yarn
| explain if there are any benefits to use just instead of
| codifying commands into the "scripts" field of the package.json?
| Commands can also be enumerated. How often would I benefit from
| just's other features?
| zemo wrote:
| package.json is specific to node projects, just can be used for
| anything. Why learn the quirks of something you can only use
| with a single programming language? I'm also a fan of the
| shebang recipes: https://just.systems/man/en/shebang-
| recipes.html
| soulofmischief wrote:
| I place package.json files into non-node projects all the
| time just for some organizational benefits like workspaces
| and scripts. As a web-first engineer this doesn't
| particularly bother me. I'll check out shebang recipes,
| thanks!
| lolinder wrote:
| We don't use Just, but we have a Makefile that doesn't take
| advantage of any of Make's dependency features just to easily
| be able to run several commands in sequence.
|
| JSON is just a really bad format for script configuration--you
| either have to string commands together on one big line with &&
| or you have to pair package.json with some other strategy for
| organizing commands. That may end up being a `scripts`
| directory with a file per script, it could be that you use a
| framework that bakes all the complexity into shorter wrapper
| commands (a la vite), or you could use something like Just to
| sequence them.
| soulofmischief wrote:
| It's not perfect but it gets the job done. Sometimes it's
| ugly but in the end it forces me to break commands down into
| subcommands, which can increase clarity.
|
| But sometimes you do have to write a collection of script
| files for complex multi-line scripts. I assumed I would still
| do that with just? Is the idea for these to all live in a
| single just file? I like having larger programs separated as
| individual files. All good points, though. I like make too,
| but it can definitely be needlessly verbose. My main thing
| would be not wanting to need users to have another binary
| installed locally. Can just live in my repository?
|
| Edit: Nevermind! https://just.systems/man/en/nodejs-
| installation.html
|
| > `just-install` will install a local, platform-specific
| binary as part of the npm install command. This removes the
| need for every developer to install just independently using
| one of the processes mentioned above.
| soulofmischief wrote:
| After digging into it more, it seems `just` requires `sh`
| to function, adding friction for Windows developers. I
| don't develop on Windows but that friction does reduce
| portability.
|
| There's ambiguity in which package to use on Node. Both
| `just-install` and `rust-just` are recommended in the docs,
| with no disambiguation. `just-install` is maintained by
| another party and adds an attack surface I'm not sure I'm
| comfortable with given my current needs. The other
| recommended package, `rust-just` is also maintained by
| another party, has bad SEO and recommends being installed
| as a global dependency.
|
| All of this just adds too much friction if one is already
| using a package.json. My monorepos frequently contain
| codebases in multiple languages and so far a package.json
| and workspaces workflow has met my needs.
|
| I appreciate everyone for answering my questions and giving
| advice.
| gurgeous wrote:
| Actually, it was package.json scripts that pushed me toward
| just! I wanted that stuff in non-node projects (python/ruby/~),
| I wanted more complicated scripts, I wanted more logging
| output, I wanted comments... For whatever reason every project
| seems to have 10-20 little commands (often interdependent) and
| just makes that a breeze.
| Izkata wrote:
| "yarn/npm install" has an artifact in the project directory, so
| here's one point for "make" instead of "just":
| start: node_modules yarn run start test:
| node_modules yarn run test node_modules:
| package.json yarn.lock yarn install touch
| $@
|
| You can clone the repo and "make test", and it'll include "yarn
| install" automatically - then on subsequent "make test", it'll
| skip it because "node_modules" is already up-to-date. And then
| include it again later if someone updated the packages. The
| "touch" is so the last-modified timestamp on "node_modules" is
| updated even if "yarn install" doesn't add/remove anything, so
| make knows it succeeded.
|
| "yarn install" is usually pretty fast when it has nothing to
| do, so I can see why people may not bother and just have it run
| every time, but patterns like this can be used for quite a bit.
| This way heavier commands don't need to be run repeatedly and
| devs don't need to know all the individual commands to run in
| sequence.
| soulofmischief wrote:
| The touch trick is nice. There's definitely merit to such an
| approach, since it provides a simple cross-platform way to
| check if node_modules exists.
|
| Though things begin to get more complicated if say, the
| project use plug-n-play resolution. `yarn` handles both
| cases.
|
| Another benefit of `"test": "yarn && <test command>"` is that
| you also make sure the project is in a buildable state when
| testing.
| sunshine-o wrote:
| I love just, this is such a great piece of software.
|
| I was thinking the other day: why don't we use just instead of
| Dockerfiles to define containers?
| diimdeep wrote:
| Just use programming language to build itself, it is even
| possible with C [0]
|
| [0] https://github.com/tsoding/nob.h
|
| If it is painful, ditch that language.
| gurgeous wrote:
| Question - mise is also incorporating a command runner. Anyone
| tried it yet? We love just, of course. Always curious about new
| tools.
| hv42 wrote:
| mise tasks (https://mise.jdx.dev/tasks/) are great!
|
| IMO, mise tasks are much better than `just`. A few things that
| make mise superior:
|
| -- solid environment variables support
|
| -- can run tasks in parallel, has a watch task feature, support
| for skipping tasks,...
|
| -- mise supports file tasks (i.e., running shell scripts, as
| many comments are suggesting here -
| https://mise.jdx.dev/tasks/file-tasks.html)
|
| -- mise tasks are defined using `toml`, and not a custom syntax
| drewbitt wrote:
| I started writing my tasks in mise (https://mise.jdx.dev/tasks/)
| instead of just, but I found that others didn't want to install
| it. Something about mise being an all-in-one tool--combining
| asdf/direnv/virtualenv/global npm/task management--made
| installing it just for the task feature off-putting. At least
| that's my theory. So, I'm back to using just. I am happy that
| there isn't a ton of pushback on adding a justfile here and
| there. Maybe it's the name--'just' feels lightweight and is known
| to be fast, so people are cool with it.
| byproxy wrote:
| I'm starting to use `mise` for tooling management and task
| running on greenfield projects, myself. Anything you feel
| `just` does better with regards to running tasks?
| jdxcode wrote:
| (author of mise)
|
| The biggest advantage just has is that it's been around
| longer, in mise tasks only came out of experimental like a
| month ago. mise tasks themselves are stable, but there are
| still experimental things and some portions that need to be
| used more--like windows. That said, most of the stuff that
| needs polish are features just doesn't even have.
|
| I had a look at the top issues for just and pretty much all
| of them I've handled in mise: https://github.com/casey/just/i
| ssues?q=is%3Aissue+is%3Aopen+...
|
| here's my unashamedly biased thoughts on why I like mise
| tasks compared to just:
|
| * tool integration - this is the obvious benefit. If you run
| `mise run test` on CI or wherever it'll setup your toolchains
| and wire them up automatically
|
| * parallel tasks - I saw this as table-stakes so it's been
| there since the very beginning
|
| * flags+options - mise tasks are integrated with usage
| (https://usage.jdx.dev) which provides _very_ comprehensive
| CLI argument support. We're talking way more than things like
| flags and default options, as an example, you can even have
| mise tasks give you custom completion support so you can
| complete `mise run server --app=<tab><tab>`
|
| * toml syntax - it's more verbose, but I think it's more
| obvious and easier to learn
|
| * file sources/outputs - I suspect just doesn't want to
| implement this because it would make it more of a "build
| tool" and less of a "task runner". I chose to despite having
| the same position that mise tasks is also not a "build tool".
| Still, I think even in the world of running tasks you want to
| only run things if certain files changed often.
|
| * `mise watch` - this is mostly just a simple wrapper around
| `watchexec -- mise run ...` for now, but it's an area of the
| codebase I plan to focus on sometime in the next few months.
| Still, even as a simple wrapper it's a nice convenience.
|
| * "file tasks" - in mise you can define tasks just by being
| executable and in a directory like "./tasks". This is great
| for complex scripts since you don't also need to add them to
| mise.toml.
|
| I have not used just very much, but I did go through the docs
| and there are a handful of things I like that it definitely
| does better:
|
| * help customization - it looks like you can split tasks into
| separate sections which is nice, I don't have that
|
| * invoking multiple recipes - I don't love how this is done
| in mise with `mise run task1 ::: task2` but I _also_ wanted
| to make it easy to pass arguments. At least for now, the
| ":::" won out in the design--but I don't like it. Probably
| too late to change it anyhow.
|
| * [no-cd] flag - both just and mise run tasks in the
| directory they're defined, but I prefer how this is
| overridden in just vs mise.
|
| * expression/substitutions - mise uses tera for templating,
| which is very flexible, but it requires a bit more verbosity.
| I like that in just you can just use backticks or reference
| vars with minimal syntax. Same thing with things like joining
| paths and coalescing. I have all of this, but the syntax is
| definitely more verbose in mise. Arguably though, mise's
| verbosity might be easier to read since it's more obvious
| what you're saying.
|
| * confirmation - I love that in just you can just add
| `[confirm]` to get a confirmation dialog for the task. I'm
| sure we'll get around to this at some point, mise already has
| confirmation dialogs so it shouldn't be hard to add. The
| tricky part will be getting it to work right when running a
| bunch of stuff in parallel.
|
| * task output - I haven't used just that much so I can't
| actually say that it's "better", but having more control over
| how tasks are output is definitely a weak part of mise right
| now and is in need of more functionality like in just how you
| can add/remove "@" to echo out the command that's running
|
| I want to call out one very silly thing that from reading
| these github issues sounds crazy. It sounds like both just
| and taskfile have the same behavior with `.env` files. In
| just and taskfile, variables defined in .env are ignored if
| they're already defined. I don't think anyone would want that
| --nobody has asked for mise to behave that way--and it
| doesn't appear either tool even allows you to change it!
| gurgeous wrote:
| Hi Jeff, thanks for creating mise! I am gearing up to
| migrate from asdf, very excited to check it out. Not
| totally sure we can adopt mise for tasks (we use just) but
| willing to give it a whirl. Putting run commands into toml
| sounds like it might be challenging, I wonder if there's
| syntactic sugar that would help.
| jdxcode wrote:
| most people just put simple tasks into toml (like `npm
| run test` or something), for anything complex, file tasks
| are much better: https://mise.jdx.dev/tasks/file-
| tasks.html
|
| file tasks are basically just a directory of bash (or
| whatever shebang) scripts, but special comments give them
| extra functionality like dependencies or defining
| flags/options.
| iKlsR wrote:
| I was half tempted to make a toy runner called `use` when I
| first learned of `just` just so I could say... just use make.
| jdxcode wrote:
| I'd be surprised if you weren't correct. Perhaps I could
| improve this a bit with the docs, but ultimately mise _is_
| complex and that will put people off no matter how good it is.
|
| I think this is all fine though. I'm hard at work improving
| mise and will continue to do so for the foreseeable future. If
| someone is hesitant, I'd rather they wait a year until more
| kinks have been worked out, docs have been improved, feature
| gaps are closed, etc. I think this is especially true for tasks
| which only came out of experimental a few weeks ago.
|
| Or people can just not use it. It's not like this is a business
| where I make more money when I have more DAU or anything. I
| just want to build a good tool for building sake after all.
| zahlman wrote:
| In the Python ecosystem there has been quite a bit of debate
| around workflow tools (Hatch, PDM, flit, Poetry etc.) I tried
| out Poetry starting in probably 2018 or so and eventually
| realized how much I hated it: it was lagging behind on
| standards and the install/uninstall process was a moving
| target. But more than that, it... was an all-in-one tool, with
| its own definition of "all", almost all of which was irrelevant
| to me and which I was simply ignoring. I never ended up trying
| other options because I realized I would still have that same
| experience - although their various definitions of "all" are
| not identical.
|
| I very much see the need in the Python ecosystem for a fully
| integrated _user-level_ tool - something that sets up
| environments and allows people to use dependencies in their own
| one-off scripts. Pipx is almost there, if you build some
| wrappers around it to deal with the fact that it artificially
| refuses to "install" what it considers "libraries" (i.e.
| packages that don't define any explicit entry points). But it
| still is a bit rough around the edges, and more importantly is
| still based on Pip which has many faults. (I don't blame the
| design of `venv` for very much if anything, even if it's not
| quite how I would do things if we could start completely fresh;
| but it could use some nicer wrappers.)
|
| But for _development_ I 've always thought it makes more sense
| to take a "Unix way" approach. Developers need the user tool
| for the basic mechanics of setting up packages, and then an
| actual _toolchain_ built around that, with the chance to select
| individual tools according to their needs and preferences.
| nunez wrote:
| Just recipes accepting command line arts and supporting
| documentation might be enough to finally push me away from Make.
| mgaunard wrote:
| I already have a command runner, it's called a shell.
|
| Apparently just also needs one to run.
| j0057 wrote:
| Can you set a variable from one task and use it from another, or
| is it a bad thing to want this?
| petabyt wrote:
| I've used make for years, even partially wrote my own make
| interpreter once, I hate it as much as anybody else. But I don't
| feel confident investing in a new tool that has widespread
| industry adoption. I wish there was a 'better make' that tries to
| replace make the same way Zig wants to replace C, where they have
| great interop and make it easy to rewrite code into the new
| language.
| dmead wrote:
| There are a ton of better makes. It still didn't matter.
| enbugger wrote:
| Any examples besides the subject?
| ttyprintk wrote:
| I'm old enough that Solaris came with SVR4 make as an
| alternative. On Windows, Borland make and nmake come to
| mind.
| GuB-42 wrote:
| "just" is not a better make, it is, well, just a command
| runner.
|
| Make is designed, well, to make stuff, it is a build
| system. But now, it is showing its age as a build system,
| and other, more advanced systems have taken over, these are
| the "better make" [1]. But it turns out that make is
| flexible and can be used for other things, namely running
| commands, and it has been rather popular for this. Problem
| is, make is still a build system at its core, and it has
| some quirks that make it less than ideal as a simple
| command runner, notably the ".PHONY" target. Just is like
| make, but it is explicitly not a build system, which allows
| it to do away with most of these quirks.
|
| So is it a "better make"? As a build system, no, it is
| intentionally a "worse make", but as "just a command
| runner", then it is indeed a "better make", and I am not
| aware of a similar project.
|
| [1] https://en.wikipedia.org/wiki/List_of_build_automation_
| softw...
| dmead wrote:
| Cmake, rake, gradle, snakemake, scons, bazel, blaze, sbt,
| cabal, stack, invoke. Blah blah blah blah
|
| What tends to happen is that some new language comes out.
| somebody decides they don't like the fact that make is
| actually more like prolog than anything else. They don't
| like prolog and just want to run some shell commands.
|
| They then decide to demonstrate the productivity of their
| new language. they implement a build system in and mostly
| for that language.
|
| People use it, a new language comes out and the cycle
| repeats.
|
| Don't waste your time. Actually learn make and just be ok
| with the fact that it does look a lot like shell/bash, but
| it isn't.
|
| Replacing make is like trying to replace the word "cool" in
| the English language. People have tried. It never succeeds
| ramon156 wrote:
| Used it in my graduate internship. It really made using the
| garbage ASP.NET commands easier. Thanks!
| silasdavis wrote:
| I'm Stockholm syndrome with make at this point. I'm not sure I'd
| want it any other way.
| olvrng wrote:
| My favorite command runner setup is just a simple bash script and
| .envrc
|
| I can put my commands in a run file, which source a simple bash
| script, and use it like: run do-foo run
| build-bar
|
| You can even `run help` to list all available commands.
|
| The setup is explained here:
| https://olivernguyen.io/w/direnv.run/
| olvrng wrote:
| Create a bash script `run`: #!/bin/bash
| set -eo pipefail run-hello() { echo
| "Hello, World!" } # -------- this is the
| magic ------- # source "scripts/_cli.sh"
|
| And source a simple script `_cli.sh`:
| #!/bin/bash set -eo pipefail show-help(){
| items=() while IFS='' read -r line; do
| items+=("$line"); done < \ <(compgen -A
| "function" | grep "run-" | sed "s/run-//") printf
| -v items "\t%s\n" "${items[@]}" usage="USAGE:
| $(basename "$0") CMD [ARGUMENTS] CMD:\n$items"
| printf "$usage" } name=$1 case
| "$name" in "" | "-h" | "--help" | "help")
| show-help ;; *)
| shift if compgen -A "function" | grep
| "run-$name" >/dev/null ; then run-"${name}"
| "$@" else echo "ERROR:
| run-$name not found." exit 123
| fi ;; esac
| luismedel wrote:
| Nice. I didn't know about Just.
|
| Just (pun intended) a personal plug: I always liked the Make ease
| of use and the declarative GH Actions phylosophy. I also like to
| have the same workflows in local and in my remote CI, so I
| recently wrote a task runner with the (IMHO) ease of use of Make
| and GH Actions-like philosophy. It still lacks good docs, but I
| use it everyday on my projects and works like a charm.
|
| https://github.com/luismedel/bluish/
|
| Some day I need to do a proper Show HN :-)
| luismedel wrote:
| I wonder how this kind of post can bother someone enough to
| downvote it. I think is related with the posted link :shrug:
| burnished wrote:
| This topic appears to have sparked some furor, maybe your
| comment got caught in the crossfire?
| nrclark wrote:
| From my perspective, Just would be more useful if it had some
| ability to skip steps where the input hasn't changed.
|
| Like maybe a Justfile's recipe could produce a "<task>.complete"
| kind of file, and could decide whether to re-run the task based
| on whether the task's inputs (or its dependencies' inputs).
|
| Also if that sounds like a useful feature, consider using Make.
| maccard wrote:
| Make solves that problem. The problem that I have is that all
| of the tools I use day to day do their own dependency tracking
| and re-run tracking. Say I want to deploy a dotnet app to a k8s
| cluster - none of helm, docker, dotnet build, dotnet test
| expose their dependency tracking in a way that is
| straightforward to use with make. The most straightforward way
| to do it is to just run the commands anyway, IME.
| hobofan wrote:
| > Also if that sounds like a useful feature, consider using
| Make
|
| Just not having that feature is _the_ defining difference in
| design between the two. If just were to ever add that it would
| likely kill its appeal. Not having that is what keeps the logic
| of a just invocation simple and what keeps Justfiles from
| devolving into the mess that Makefiles tend to with entangled
| build targets.
| tgmatt wrote:
| I'm surprised nobody mentioned Rake yet. Having the full
| capability of Ruby and whatever gem you want makes it a dream for
| these kind of tasks. Absolutely love it.
| ufmace wrote:
| That's what I dropped in to say. I've used most of them, and I
| think Rake is my favorite.
|
| Pretty much all of the others are shell command runners with a
| couple of extra bits bolted on. Well and good most of the time,
| but it's another language to learn, and you're mostly SOL if it
| doesn't support something you want to do nicely.
|
| With Rake, you get the same basic ability to do pre-set shell
| commands as the others, a single one or a sequence. But you
| also have the full power of Ruby, a full-fledged programming
| language, if you want to do anything more complex.
| flomo wrote:
| I was looking for this comment, because rake is great. One big
| thing is it never felt good imposing Ruby on a (say) a JS
| project (and I'm not sure of the current state of macos default
| ruby), so next time this comes up, I will be taking a look at
| just.
| tomjakubowski wrote:
| One reward you get for allowing yourself to become brainwashed by
| Bazel is you get a pretty nice task runner in every project that
| you've brought into the fold.
| okanat wrote:
| Reliance over a Posix shell basically prevents me from using
| Just. Using bash from Git on Windows is a very weird choice.
| 25thhour wrote:
| I'm also using a global justfile (`-g`) [1] to serve as a
| convenient location to aggregate any convenience functions, as
| well as call out to any standalone scripts as necessary.
|
| You can also 'convert' all recipes to aliases so you get the best
| of both worlds, the ability to call with `just -g foo` or `foo`,
| from anywhere.
|
| The docs example [2] uses a `user` justfile, but the principal is
| the same for global. for recipe in `just
| --justfile ~/.user.justfile --summary`; do alias
| $recipe="just --justfile ~/.user.justfile --working-directory .
| $recipe" done
|
| Most recently I've started using `fzf` and `bat` to allow
| interactive selection of recipes with syntax highlighted
| previews: _choose: @just -g --summary | \
| tr ' ' '\n' | \ sort -r | \ fzf --multi
| --preview 'just -g --show {} | bat --color=always -l just -pp' |
| \ xargs just -g
|
| Now with a global `alias ji="just -g _choose"` I can
| interactively choose a recipe if I need a reminder of what I've
| set up.
|
| This was inspired by the native `--choose` flag which does
| something similar, but by using `--summary` here, all recipes,
| including those that take arguments *, are listed, as well as any
| nested modules.
|
| And because you can use any shebang, you can also write little
| python scripts to run with `uv`, including those with
| dependencies [5] declared in the shebang: # list
| Cloudflare accounts accounts: #!/usr/bin/env -S uv
| run --script --with cloudflare --python 3.13 from
| cloudflare import Cloudflare client = Cloudflare()
| accounts = client.accounts.list() print(accounts)
|
| ...here with inline metadata: # list Cloudflare
| accounts accounts: #!/usr/bin/env -S uv run
| --script # /// script # requires-python =
| ">=3.13" # dependencies = [ # "cloudflare",
| # ] # /// from cloudflare import Cloudflare
| client = Cloudflare() accounts = client.accounts.list()
| print(accounts)
|
| [1] https://just.systems/man/en/global-and-user-justfiles.html
| [2] https://just.systems/man/en/global-and-user-
| justfiles.html#r... [3] https://just.systems/man/en/selecting-
| recipes-to-run-with-an... [4]
| https://github.com/charmbracelet/gum?tab=readme-ov-file#inpu...
| [5] https://docs.astral.sh/uv/guides/scripts/#running-a-
| script-w...
|
| * interactively selected recipes that take arguments won't work
| by directly passing to `xargs` here, but in some cases where I
| _do_ want that flexibility I just add a condition in the recipe
| to prompt for input, with `gum input` [4]. Flexibility. This is a
| belt and braces approach and only used where necessary as the
| `fzf` preview will have made it clear that a recipe takes
| arguments. [positional-arguments] foo
| $bar="": #!/usr/bin/env bash if [ -z "$bar"
| ]; then bar=$(gum input --placeholder "bar")
| fi echo "looking up $bar"
| jdxcode wrote:
| I think you'd like what I've done with mise. You can have tasks
| in your global config (~/.config/mise/config.toml) which by
| default are shown no matter where you are. `mise run` will show
| a selector by default of all tasks available, so no need to
| manually setup fzf. Shebangs work the same. Commonly, mise
| users would also put "uv" into their config so other users
| don't need to set that up separately from mise itself.
|
| Interactive inputs are something I'm planning on shipping
| relatively soon. It would not be hard to do--I've got the ui
| components to do it and the data model supports it.
| sebmellen wrote:
| Justfiles are really awesome for repos where you have to use a
| bunch of complex, long to type CLI integrations. Especially if
| you're using Deno scripts that all have different permission
| flags...
| PhilippGille wrote:
| Several comments mention Task/Taskfile already, which is very
| similar in that you define tasks in YAML.
|
| I think it's worth mentioning Mage/Magefile [1][2] as well, where
| your tasks are actual Go code. Similar to how Rake is for tasks
| in Ruby code.
|
| It's useful when you have complex tasks.
|
| It's like using Pulumi instead of Terraform.
|
| [1] https://magefile.org/
|
| [2] https://github.com/magefile/mage
| jmartin2683 wrote:
| I love just! Any way to avoid remembering things is great.
| rout39574 wrote:
| Why is "Just" superior to any other e.g. bash script with a bunch
| of subcommands?
| gedw99 wrote:
| I am really moving spok
|
| It's golang based but very like make.
|
| https://github.com/FollowTheProcess/spok
| shikaan wrote:
| I built something similar a couple of years back. Glad to see I
| wasn't alone in my itches
|
| https://github.com/shikaan/shmux
| quotemstr wrote:
| Uh, isn't this just Make? I'd rather people run `make this` and
| `make that` than install a new tool to do the same damned thing.
| Sometimes software is just "done" and doesn't need to be
| reinvented.
| jdxcode wrote:
| no flags, no parallel tasks, no skipping tasks unless files
| change, no watching for changes
|
| come see a modern task manager: https://mise.jdx.dev/tasks/
| efitz wrote:
| This looks cool, but why not have vars in .env files?
| jdxcode wrote:
| you can do that too:
| https://mise.jdx.dev/environments.html#env-file
|
| but sometimes you don't want to make it an env var--just
| supports this too through the `export` keyword
| dr_kretyn wrote:
| Seems that I'm the only one who opened up the website and didn't
| know what was going on. At least two sentences what the "just"
| is, otherwise it's "if you, you know" and that isn't inviting
| page.
| csomar wrote:
| I used this until AI became good enough. Now, for most purpose, I
| can just declare what I want to be done/executed and get perfect
| bash for it. I have a relatively complex Makefile that build
| graphql schemas and sets them up. It'd have been a no-go given
| how weird bash syntax is; but now I can get it generated and
| working from pretty much the first try.
|
| There is lots of bash around and it's a very simple language, so
| AI models are pretty good at it.
| mikojan wrote:
| What does that mean? You have a huge LLM generated bash script
| instead of a human-readable makefile? I do not understand.
| CGamesPlay wrote:
| My favorite entry in this space is Argc. I like it because the
| only "new syntax" it introduces is metadata comments, and the
| rest is pure bash. The maintainer is also best-in-class in terms
| of responsiveness.
|
| https://github.com/sigoden/argc
| WuxiFingerHold wrote:
| I find it more powerful and from a certain point easier to create
| the tooling using the projects programming language. Every dev
| should be familiar with that language and ecosystem. E.g. for
| project that had several tools - Rust (server), .NET and Node
| (CLI tools) and Svelte (frontend) - I wrote _all_ operational
| tools in Typescript and run them using Deno. Very clean and
| powerful (typesafe, composable, Deno std lib). You can add all
| kind of stuff like timings, logging, checks, whatever ...
| grantcarthew wrote:
| Nobody: Let's write all of our scripts in YAML
|
| Me: !
| dimator wrote:
| I use it as a somewhat more sane way of collecting my repetitive,
| project specific commands, without having to rely on shell
| history.
|
| I'll just plop my project-specific workflows (series of shell
| commands) into a Justfile (that I don't commit, it's just for
| me). That allows me to be more rigorous and structured with how
| I'm iterating on a project.
|
| It has syntax and semantics that are sufficiently saner than
| make, so I don't need to know a lot to be productive.
|
| If I come back to a project after a couple weeks, I don't need to
| spelunk shell history. Just --list is enough to get back up to
| speed with how I was iterating.
| jstrieb wrote:
| In case you want to run Justfiles in places where you can't
| install the Just binary (for whatever reason), I wrote a compiler
| that transforms Justfiles into portable shell scripts that have
| byte-for-byte identical output in most cases.
|
| https://github.com/jstrieb/just.sh
|
| Previous HN discussion:
| https://news.ycombinator.com/item?id=38772039
| hiAndrewQuinn wrote:
| Fantastic! This solves my big fear around getting used to such
| a tool.
|
| My work primarily involves 'nix boxes that have to be very
| locked down and will be left in a place basically untouched for
| 20 years after I finish setting them up. Getting a reliable new
| binary of any sort on them is quite difficult, not least
| because we need to plan for things other far future people
| might be able to discover for troubleshooting down the line.
| Kharacternyk wrote:
| Could you tell more about these 'nix boxes? Sounds very
| interesting.
| miroljub wrote:
| Why would you care now? In 20 years somebody else would be
| paid to fix it.
| k_bx wrote:
| I see more projects switch to PIXI, another Rust-written piece of
| software. RERUN was the one I follow the most
| https://github.com/rerun-io/rerun
|
| It looks like much more than just command runner, but my projects
| happen to be needing much more than that too.
| udev4096 wrote:
| Can anyone give me an example where I can actually replace my
| bash scripts with just? I don't see a point in using it if I can
| simply write a bash script (at least their examples are very
| easily replaceable)
| porkbrain wrote:
| Many reasons are already mentioned in other comments. I'd add
| the following nice-to-have. Sometimes you'd find it
| easier/preferable to run some scripts with some other shell.
|
| You can set the shell for some commands, for example:
|
| ```
|
| set shell := [ "python3", "-c"]
|
| # I can run python!
|
| [no-cd]
|
| foo-bar: @import sys; major, minor =
| sys.version_info[:2]; assert (major, minor) >= (3,
| 7), "This script requires at least Python 3.7. Please link
| \"python3\" to Python 3.7 or higher and try again."
|
| ```
|
| And the API for your commands stays consistent for a very
| little effort. Of course you can achieve all this with just
| bash scripts but I find it faster and easier to provide a good
| devex this way.
| bjackman wrote:
| I think of you're ok with "just writing a bash script" the tool
| is not for you
|
| Everything I do with Just can pretty easily be done with Bash.
| But, doing it with bash is yucky. Doing with with Just is
| comfortable. If you don't have the yuck factor then I'd say you
| can just stick with Bash!
| ndr wrote:
| I've been using babashka tasks [0] for a while. It has a nice api
| to run shell commands but it's all clojure based.
|
| Am I missing out on justfiles? It seems to be quite popular among
| rust/nix circles but I'm afraid it's going to be yet another
| instance of Greenspun's tenth rule.
|
| [0] https://book.babashka.org/#tasks
| nektro wrote:
| use this in my projects and love it
| gutomotta wrote:
| I saw many projects like this a while ago, and, although they all
| seemed great, I kept wondering why do I need such a complex thing
| just to save/run a bunch of scripts?
|
| I ended up building my own script runner, fj.sh [1]. It's dead
| simple, you write your scripts using regular shell functions that
| accept arguments, and add your script files to your repos. Run
| with "fj myfunc myarg ...". Installation is basically downloading
| an executable shell script (fj.sh) and adding it to your PATH.
| Uninstall by removing it. That's all.
|
| I'm not saying 'just' is bad--it is an awesome, very powerful
| tool, but you don't always need that much power, so keep an eye
| on your use case, as always.
|
| [1] github.com/gutomotta/fj.sh
| junipertea wrote:
| There is irony in "I don't understand why people do X and ended
| up doing X but simpler"
| zahlman wrote:
| There is nothing at all ironic, inconsistent or otherwise
| strange about "I don't understand why others' implementations
| of X are so complex".
| hk__2 wrote:
| 'Just' too was simple at the beginning [1], but with time and
| usage things always become more complex that some script you do
| for your own specific use-case.
|
| [1]: https://github.com/casey/just/tree/v0.2.23
| apitman wrote:
| You didn't mention it's written in Rust. Is that allowed?
___________________________________________________________________
(page generated 2024-12-08 23:01 UTC)