461 karma · joined September 27, 2016
Secondarily, do the same issues not apply to the Linux API as to a hypothetical ABI? If the API changes, don't userspace applications still need to be updated and/or recompiled accordingly, or suffer breakage? At some level, whether it's an ABI, a statically linked API, or a dynamically linked API, there always has to be some interface between applications and the operating system, and breaking changes to that interface must be managed with care.
It comes down to where you decide to draw that interface, and I think the ABI is just a better place to draw it from a user's perspective. This way, applications don't need to be recompiled to work on newer operating system versions, and given how challenging and painful it can be to compile applications reproducibly, and how many applications are only provided in binary form to begin with, this seems like a worthy goal.
To summarize: it is a well-known fact that those people who must want to rule people are, ipso facto, those least suited to do it.
To summarize the summary: anyone who is capable of getting themselves made President should on no account be allowed to do the job."
- Douglas Adams
It might be cool if uv ignored dependency versions newer than the script's last modified timestamp, but this behavior would probably need to be very explicit to avoid the situation where a working script is mysteriously broken by making an innocuous change which updates its last modified timestamp, causing uv to resolve a newer, incompatible dependency version.
[0] https://docs.astral.sh/uv/guides/scripts/#locking-dependenci...
Now you have to use the `docker_image` resource to build a local image on the build host, and then use the `docker_registry_image` resource to publish it to the registry. In a CI/CD scenario with ephemeral runners, there will never be a local version of the image on the build host, so the image will always be rebuilt on every Terraform run, even if there are no changes to it.
It's a tricky problem to solve from a provider design standpoint, since building a Docker image necessarily creates a local Docker image on the build host, which may not be a desirable side effect for the `docker_registry_image` resource to have and raises other design questions with no universal answers (Should it delete the local image after building? What if there's already a local image with the same name/tag, but it's not in the Terraform state; should it use the existing one or build a new one and overwrite the existing one? If the `docker_registry_image` resource is removed, should any corresponding local images also be delete? etc.)
It's not solving the underlying problem: that build systems are often impure and sometimes nondeterministic. It also tries to solve a bunch of adjacent problems, like providing a common interface for building many different types of package, providing a common configuration language for builds as well as system services and user applications in the case of NixOS and home-manager, and providing end-user CLI tools to manage the packages built with it. It's trying to be a build wrapper, a package manager, a package repository, a configuration language, and more.
1. Literal values only (objects, arrays, strings, numerics, booleans, maybe datetimes), a la JSON, with standardized semantics
2. Literals, variable definitions and references, pure function definitions, and pure function calls, but prohibiting recursion, such that evaluation is not Turing-complete and any value is guaranteed to be able to be evaluated into its literal form in finite time
3. All of the above plus recursion and impure, side-effectful functions, custom type definitions, etc.
This way, implementing a literal parser in other languages would be comparatively straightforward (much like JSON), since it wouldn't have to support variables or functions, but it would also be possible to define values using variables and pure functions (much like HCL or Nix) and then use the language's own evaluator binary (or perhaps a wrapped FFI library) to safely convert these into literal values that another language can parse, while guaranteeing that evaluation will not have side-effects. It would also leave open the escape hatch of using a "full" Turing-complete language with side-effects and recursion, while ensuring that using that escape hatch is a deliberate choice and not the default.
I'm sure there are a few additional or hybrid levels that could be useful too (2 but with recursion? 1 but with variables?) but this seems like it would be a solid starting point.