Subject: Re: NNCP in Debian/Ubuntu Update

From: Sergey Matveev <[email-masked]>
Date: Tue, 21 Sep 2021 13:10:56 +0300

*** John Goerzen [2021-09-20 16:13]:
>Fundamentally I can't just change that on my own, so our conversation here is
>discussing something that "is what it is", regardless of whether we agree with
>it.  But, hey, I like conversation :-)

I understand that of course :-). Here I just chatting around too. Just
my two cents.

>In Rust, there is a Cargo.toml, which defines the general requirements for
>dependencies (ie, package X, version 0.2.*) and then a cargo.lock which
>records the precise version and hash of the dependency used for a canonical
>build.

Go's go.mod is some kind of cargo.lock analogue -- where exact
tag/commit of the dependant source code is set. And go.sum for
assurance of exact source code contents.

>The pro is, of course, that you can easily get a theoretically identical
>build from anywhere.

And that is completely worth of it!

>And the con is that you may have dozens of different versions of the same
>package in use on a system, making it difficult to patch bugs and security
>issues.

And one point of dynamically linked libraries is similar: easy upgrade
path of some single globally shared library. But Go authors, Plan9
authors (same subset :-)) are heavily against dynamic linking concept
(me too). Of course I can not put words in their mouths, but as I
understand, there is assumption (I heavily support too) that software
must be easily and quickly build and rebuilt. Of course each software
package has to have the source code. So in some hypothetical Plan9, if
there is need to upgrade its "OpenSSL" (actually there is no such task
at all, because cryptography related tasks are just offloaded to
separate (microservice) daemon -- single piece you need to
update/rebuild), then you just rebuild every dependency. With Go, pure C
(in most cases) -- compiling is very very fast. If someone needs to
update Go itself (with its pretty feature-wide native libraries): just
find all packages containing go.mod and run "go build" to rebuild
literally every Go software in several minutes. If you need to update
some dependency like golang.org/x/crypto, then probably "go get -u
golang.org/x/crypto" in every Go's module will be enough, with later
rebuilding. Problem of library updating and fixing is very minor one,
not worth of using complexities like dynamic linking.

Moreover dynamic linking does not give any guarantees that everything
will go fine, because some mistakenly made backward incompatible API
changes could break many things. So it is just some kind of good luck
and still existing programming culture, that we can transparently do
those upgrade paths. I was (and unfortunately still) Python programmer
for many years and see that people are just *fully* incapable of
providing correct dependency information at all. Python heavily relies
(well, they try to move to Go/Rust-like lockfiles) on semantic
versioning -- that is good. But it is enough to have only single
package, that mistakenly (human factor) break it and everything could go
wrong and won't install at all. So Go/Rust's behaviour is some kind of
Holy Grail :-) -- this is the only thing that can guarantee working
packages and dependencies. So in my opinion it is just much easier to
rebuild all dependant software, than to blindly believe that yet another
dynamic library update will go smoothly. No, people are incapable of
doing this.

>Tradeoffs abound.  What's right for Debian isn't right for everybody.
>Debian prizes stability -- that is, an installed system keeps working in the
>same way for a long time.

I used Debian for 6 or 7 years and truly remember its stability,
comparing to all other popular distributions. I am definitely not a
bleeding edge fan too :-). I installed Debian only once: 4.0 and made
dist-upgrade/upgrade till 6.x versions.

But... the world before modern dependency systems (like in
Go/Rust/someone other I presume) was really so awful, that Debian's
approach was good. But with Go... in my opinion it is hardly acceptable.
And your example with blake3+cpuid shows its deficiency: Go's modules
depend on exact version of software, so in theory nearly every library's
commit have to be packaged as golang-github-XXX-gHASH, but you got some
incompatibility and game is over :-). Either you keep each library's
version somewhere under little chroot:
/usr/local/lib/golang-github-XXX-gHASH and give "-I"-like points to Go
compiler where to find exact versions, or you have to rewrite the
software. I can not say "fix" software, because probably API change is
not related to bug of anything similar. Basically Nix approach solves
that problem: it keeps any kind of version under different paths,
symlinking/including only necessary and required ones for each package
independently. Moreover when you "give" different cpuid/blake3/whatever
library version, it means that the program you build does not conform to
its go.mod/go.sum. I would call it: broken build. Once I met funny
thing: I used library that made incorrect/invalid tar archives, but I
did not note that they were invalid and my code was fully dependant on
that buggy behaviour. After library update I found that tar archives
were not working anymore as expected. But I still anyway could use and
build that bug-compatible code without any problems. Debian won't allow
that, because program's author has no control over exact library version
(or each version has to be separate package in separate directories, as
in Nix). In my opinion Debian just breaks very good Go's approach of "do
exactly as I say" (use exactly that code, with that checksum). Debian's
built package may vary much from the original/vanilla version. Well, it
is just another point of view how things should be done right, of course.

>not really worth introducing multiple cpuid versions for

Go assumes that any API change leads to creation of completely different
library (namespace): github.com/klauspost/cpuid and github.com/klauspost/cpuid/v2
are completely different independent libraries.

>you could pull in newer cpuid and blake3 into your tarballs, if you like.

Yep, done: http://www.git.cypherpunks.ru/?p=nncp.git;a=commitdiff;h=dc6e5f1898c14e61985fd452c3fcf92914ca1207

>Ahh, well we have a tool called reportbug that captures all of that with a
>bug report (or at least enough for a Debian maintainer to look it up in the
>project databases), and sends it to the Debian bug-tracking system.

Ah, good!

>Haven't heard of Stow, but I have heard of Gentoo.  I tried it for a spell.

https://www.gnu.org/software/stow/
I used it initially for tracking my dotfiles
(http://www.git.stargrave.org/?p=dotfiles.git;a=tree), but later more
and more used for working with manually build software. It is just some
kind of symlink manager :-)

-- 
Sergey Matveev (http://www.stargrave.org/)
OpenPGP: CF60 E89A 5923 1E76 E263  6422 AE1A 8109 E498 57EF