Idea for packaging rust apps

2024-05-22 Thread Murilo
Hello, I hope this is the right place for this, apologies if it isn't. 

I'm working with a friend on a cargo importer that lowers the entry barrier 
and the maintainability costs for packaging rust apps in general, without 
sacrificing Guix dependency tracking and reproducibility of rust packages. 

When you get used to the tool, you can pretty much package rust apps with 
all the dependency chain very easily (I just packaged [1] texlab for my 
channel earlier this morning in less than 5 minutes, and i can easily 
update apps to the latest version in less than a minute). 

Progress is being tracked in [2] if anyone wants to check it out or 
contribute to it. It is currently missing a lot of features, but we hope 
to improve the user experience of the tool in the near future. 

It is a very simple tool, it essentially parses the Cargo.lock file and 
extracts all the relevant information for constructing the rust package 
definitions of all the cargo-inputs and the package itself, and outputs 
to stdio a guile module containing all the needed cargo-input chain as 
guix packages, with all the cargo-inputs self-contained and versions all 
sorted out for a working final package build. 

This way a packager only needs to focus on the actual package they are 
trying to build, instead of worrying about its cargo-inputs. 

Due to how cargo-inputs are organized in gnu/packages/crates-*.scm, and 
some current packaging guidelines for crates on Guix, we cannot simply 
contribute these self-contained packages generated directly from the 
Cargo.lock, thus requiring to use the guix crate importer and spending 
a lot of time fixing dependencies and worrying about other packages 
breaking in the process. 

I would like to propose some discussion around a better way of organizing 
the rust packages and its cargo-inputs in (gnu packages) for building 
rust apps that only need sources as cargo-inputs: 

1) Create a new directory at gnu/packages/rust/ in which a contributor 
can commit self-contained rust apps scm modules. 
2.1) Add a new module at gnu/packages/rust/my-rust-app-1.scm 
2.2) Add a new module at gnu/packages/rust/my-rust-app-2.scm 
3) All package definitions inside gnu/packages/rust/*.scm which are 
source-only (#:skip-build? #t) should not be exported. 
4.1) gnu/packages/crates-*.scm will not cease to exist, existing rust 
apps packages that have a Cargo.lock could gradually be migrated to the 
new organization 
4.2) libs which need to be built can still live in 
gnu/packages/crates-*.scm 
5) A (define-public my-rust-app-1 (@@ (gnu packages rust my-rust-app-1) 
my-rust-app-1)) or equivalent could be done in a (gnu packages category) 
module to export the rust app in the desired category. 
6) Unlike nix (which also parses the Cargo.lock in the build system), 
we don't lose the ability to make snippets for sources this way. 
7) For updating/maintaining a rust package defined this way, one would 
be able to simply re-run the guix tool, and replace the 
gnu/packages/rust/my-rust-app.scm file, only copying over the final 
relevant package definition for the rust app with its tweaks for building, 
and passing over the new cargo-inputs generated by the guix tool. 

I believe that by only changing the way things are organized and having 
a guix tool that generates self-contained package definitions from 
Cargo.lock, it would be possible to greatly improve the time required 
for contributing new rust apps packages and maintaining them on Guix. 

Things don't need to be the way I described here, these are just my 
initial thoughts after several failed attempts and wasted time trying 
to contribute rust apps to Guix, I'd like to discuss workarounds and if 
the benefits are greater than the disavantages for an approach like this. 

The tool we made works really well for packaging for our personal channels, 
I am very satisfied with how easy it is, and I think Guix could benefit a 
lot by adopting a similar approach. 

What am I missing here? Are there any disavantages to this approach? 
Anything that would break from it if adopted on Guix? 
Any questions or suggestions? 

Murilo 

[1] 
https://codeberg.org/look/saayix/commit/c7643943545d62baba80cccee1650ebf94362858
 
[2] https://git.sr.ht/~look/cargo2guix



Re: Idea for packaging rust apps

2024-05-25 Thread Murilo
Hi MSavoritias,

> I wanted to ask, are you also aware of the antioxidant effort? 
> https://notabug.org/maximed/cargoless-rust-experiments

I was not aware of it at all, thank you for enlightening me about the 
effort.

> I was wondering of the differences since your build system seems to 
> still be using cargo under the hood instead of rustc.

Yes, you are correct. It really does nothing special except making 
packaging of rust apps for the end user extremely easy. This approach 
still uses the cargo-build-system, it is not a replacement for it, 
thus carrying all the cargo (and cargo-build-system) flaws along with 
it.

The antioxidant-build-system, on the other hand, aims to mainly solve 
the inefficiencies of the cargo-build-system and cargo itself. After 
looking at some mail exchange on the antioxidant effort, it will be 
hopefully much nicer to make rust packages once the rust-build-system 
is merged, and it will be a much better approach for Guix than what I 
am currently suggesting.

I believe my approach with cargo2guix and transitively generating guix 
package definitions from Cargo.lock will mainly target user's Guix 
channels because of the simplicity of the packaging process. While it 
is better than what we currently have on Guix, it is nowhere ideal for 
Guix as the antioxidant effort is, because of CI and the amount of 
packages Guix has.

Thank you once again for making me aware of antioxidant and the future 
rust overhaul on Guix.

--
Best regards,
Murilo



Re: Securing personal forks (Was: Discussion with Codeberg volunteers)

2025-02-12 Thread Murilo
Hi Felix and 45mg,

I came up with a quick dirty hack for solving my authentication problems on guix
forks and channel forks, and upon seeing this discussion I thought I'd share
some bits.
It's a very simple trick, only requires (roughly) 3 lines of code in
'guix/git-authenticate.scm'.

See [1] for the diff (in the guix-hacks branch), just search for the 'init auth
hack' commit (I rebase it all the time so its better if you search for the
commit as any links will get broken soon).

If you don't want to, it goes something like this:
--
...
  (unless (or (member (openpgp-public-key-fingerprint signing-key)
  (commit-authorized-keys repository commit
  default-authorizations))
  (member (openpgp-format-fingerprint
(openpgp-public-key-fingerprint signing-key))
  '("          ")))
...
--

After I add my fingerprint to the 'or' condition, I also add my public key to
the 'keyring' branch of the fork [2].
After that we need to bootstrap it once with '--disable-authentication', and
after bootstrapping it once you can freely rebase with only '--allow-downgrades'
(or don't rebase at all, your call) and enjoy full authentication on your fork.

No need to mess with introductory commits, you can just keep guix' default one.
No need to edit '.guix-authorizations'.

It also works for authenticated channel forks, you just need to add your key to
the 'keyring' branch of the channel fork and it will work.

Just sharing this quick hack I use, its far from ideal but it works for me, and
seeing this discussion I thought it might be useful for someone in the meantime
:)

Best regards,
Murilo

[1] https://codeberg.org/look/guix/commits/branch/guix-hacks
[2] 
https://codeberg.org/look/guix/commit/8e2902aabb14e93864920bac51a178aeedf8a563



Re: How to move forward about Rust? antioxidant, cargo2guix, etc.

2025-03-06 Thread Murilo
On Thu Mar 6, 2025 at 2:24 PM -03, Efraim Flashner wrote:
> On Wed, Mar 05, 2025 at 09:20:50PM +0800, Hilton Chain wrote:
>> 1. Unpack package source then update lockfile:
>> --8<---cut here---start->8---
>> cargo generate-lockfile
>> --8<---cut here---end--->8---
>> 
>> 2. For adding new packages check output of ‘cargo audit’ and ‘cargo license’.
>
> These two were easy.  I realized later that we could forgo running
> 'cargo generate-lockfile' if we wanted to use the Cargo.lock that
> already exists (if it does), but we probably want to make sure we have
> more up-to-date dependencies as much as possible.  I could see, as part
> of a rust-team branch, going through and updating the lockfile every now
> and then even if there is no update to the actual package, as the
> dependencies get updated upstream.
I think always having the most up-to-date dependencies is a good thing as well.

Just something to keep in mind when doing this is that when we ship the same
lock as the upstream release tag, we are making sure the final program will
behave as closest as possible to the release version shipped upstream.

This is a good thing for upstream because it can receive bug reports from guix
users without much worry about the dependency chain being different and we are
more likely to have the same issues as upstream has.

So while I think the chances are low, there's always a chance of something
breaking at runtime if we start bumping the locks. Even if the semver is
compatible you never know how the final program might behave.

Again, not against it, just something to keep in mind.

>> 3. Update module
>> --8<---cut here---start->8---
>> guix import --insert gnu/packages/rust-crates.scm crate --lockfile=<...> 
>> <...>
>> etc/teams/rust/cleanup-crates.sh
>> --8<---cut here---end--->8---
>
> I got tripped up with this a bit. --lockfile=path/to/lockfile 

Also, not sure if its a shell thing, but I spent a couple minutes until I
realised that passing '~' to --lockfile didn't work (it triggered the normal
crate importer, without lockfile, instead) like so:

---
Does not work as expected:
$ guix shell -D guix -- ./pre-inst-env guix import \
--insert gnu/packages/rust-crates.scm crate \
--lockfile=~/path/to/Cargo.lock 

Works as expected:
$ guix shell -D guix -- ./pre-inst-env guix import \
--insert gnu/packages/rust-crates.scm crate \
--lockfile=/path/to/Cargo.lock 
---

> I had 4 dependencies which needed git-fetch, and I packaged them in
> rust-crates.scm also.  I tried changing the names to
> rust-xx-for-uv.tar.gz, but that didn't trick cargo into unpacking them.
> In the end I had to add them as inputs and copy them over manually.  One
> of them, version-ranges, was inside a directory of another one, which
> was annoying to figure out, and I think would've needed manual
> intervention even if git sources were unpacked automagically.

A bit of a hack I do is to use the forge archive links for these, for example:
---
(origin
  (method url-fetch)
  (uri 
"https://github.com/pythonesque/shaderc-rs/archive/f2605a02062834019bedff911aee2fd2998c49f9.tar.gz";)
  (file-name (string-append name "-" version ".tar.gz"))
  (sha256 (base32 "14na50a585lb0pkdz3kraw2sgk8qjd78972aimcwdlkl9kyvvd0z")))
---
Then it already comes in '.tar.gz' and gets handled by cargo-build-system.
Not the best, but it gets the job done and I think its easier than modifying the
phases to add the extra sources.

On Wed Mar 5, 2025 at 10:20 AM -03, Hilton Chain wrote:
> My current workflow uses these packages:
> --8<---cut here---start->8---
> guix shell rust rust:cargo cargo-audit cargo-license
> --8<---cut here---end--->8---
>
> 1. Unpack package source then update lockfile:
> --8<---cut here---start->8---
> cargo generate-lockfile
> --8<---cut here---end--->8---
>
> 2. For adding new packages check output of ‘cargo audit’ and ‘cargo license’.
>
> 3. Update module
> --8<---cut here---start->8---
> guix import --insert gnu/packages/rust-crates.scm crate --lockfile=<...> <...>
> etc/teams/rust/cleanup-crates.sh
> --8<---cut here---end--->8---
>
> 4. Check module diff, content of sources marked as TODO and output of
> 'check-for-pregenerated-files phase.

I tried it on a couple packages, the importer seems to work really well, so far
so good.

> I added etc/teams/rust/rust-crates.tmpl in case multiple modules are wanted.
> But I still hope you to try the one-module approach first :)

I'm still a bit concerned about having too many git conflicts to solve when
multiple patches from different people start coming a

Re: How to move forward about Rust? antioxidant, cargo2guix, etc.

2025-02-24 Thread Murilo
Hi Simon, thanks for bringing up the discussion again.

On Fri Feb 21, 2025 at 11:23 AM -03, Simon Tournier wrote:
> How does it compare with antioxidant?  And your (Nicolas) ideas?

Antioxidant and Nicolas proposal is for a new build system (rust-build-system)
in Guix best aligned with we already do for other languages, which is using
libs shared and re-using previously pre-built stuff as inputs for a new package
output.

Using rust-build-system comes with a major advantage:
- Lower build times, since we are only building every rust package once;
- Meaning Cuirass will build rust packages much much faster than when using
cargo;
- As an indirect consequence, other packages in guix are evaluated faster.

In contrast, my proposal is to continue using the cargo-build-system, but
reorganize how we define and accept contributions for rust packages on
(gnu packages *) by transitively generating guix package definitions from
Cargo.lock.

>From my perspective it makes contribution easier because you need only to
generate the module contents, with, say, 'guix import' and send that isolated
module.
The module contents could be only origins, as Ludo' suggested, together with
the actual package definition for the rust app you're packaging.

It also makes the maintainability of the rust ecosystem in guix easier:

- "I want to update the 'melon' package." (the current guix way)
* I run 'guix refresh -u melon' to update the version and hash.
* 'guix build melon'
* Oh, guix has 'rust-orange@1.1.0' but it needs 'rust-orange@1.2.0'.
* I'll just update 'rust-orange'!
* But then I'll have to fix the 'strawberry' package that requires '= 1.1.0'.
Notice that because rust packages use #:cargo-inputs there's no easy and
documented way way to check the above, AFAIK, until cuirass complains about it.
* I'll just make 'rust-orange-1' the new 1.2.0, and make a new 'rust-orange-1.1'
for the 'strawberry' package.
It's easier to do this instead of patching the Cargo.toml because you don't
need to test if 'strawberry' works - a package that you never used before and
have no idea what is, you're just trying to update the 'melon' package.
When 'strawberry' updates, it will probably leave 'rust-orange-1.1' hanging.
* Make sure every affected package builds (even libraries which IMO shouldn't
be built).
* Write multiple commit messages for each package change across diferent 
modules.

- "I want to update the 'melon' package." (my proposed way)
* 'melon' package is in 'gnu/packages/rust/melon.scm'.
* I run 'guix refresh -u melon' to update the version and hash.
* I run 'guix import cargo melon', it fetches the 'Cargo.lock' from the origin,
and generates the dependencies.
* I delete the entire 'gnu/packages/rust/melon.scm', except for the 'melon'
package, and paste the new generated cargo-inputs.
* Update 'melon' #:cargo-inputs to the newer generated ones.
These steps could be automated with a tool (perhaps attached to 'guix
refresh') to automatically do these trivial steps if we agree on sort of a
pattern/template for organizing rust apps.
* One single commit to the module update (because updates mostly won't affect
other modules).

>From my experience using this workflow on my personal channel I can package
most rust apps in less than 10-15 minutes (including build time), and updates
are really trivial to the point I can do even major version bumps in less than
2 minutes (excluding build time, and including some manual editor steps which
could be automated).

I'd like it too if we could get rid of #:cargo-inputs and use regular package
inputs, as Efraim noted.
I might be mistaken but I believe the new 'zig-build-system' does something
similar to how cargo works when building, and it used to have #:zig-inputs
in the WIP implementation which was rewritten later as regular input fields,
perhaps we could do some analogous work for 'cargo-build-system'.

Best regards,
Murilo



Re: How to move forward about Rust? antioxidant, cargo2guix, etc.

2025-02-26 Thread Murilo
On Wed Feb 26, 2025 at 12:30 PM -03, Efraim Flashner wrote:
> I was looking closely at cargo2guix earlier this week, and I hacked up
> that if a [[package]] had a source but no checksum it was a git
> reference, and if it had no source and no checksum then it must be
> inside the workspace.

Yes, this is true. I've known this for a while but never had the motivation
to implement some logic for it in cargo2guix. I've been removing the workspace
cargo-inputs by hand until now - thanks for the patch by the way, I'll look at
it later :)

> Looking at guix/build/cargo-build-system, the "easiest" option would be
> to take the git-checkout and then turn it into a .tar.gz.  Otherwise
> crate-src? and 'configure would need to be adjusted to handle git
> checkouts.

I think so too, while its easier it feels a bit hacky, but it should do the job
for now. We could always do a proper support for git checkouts later.

---
(A bit of a parenthesis)
Perhaps its also a good time to add "--offline" to all cargo invokes to
effectively prevent it from executing online operations.
---

> Would it be easier to have 1 package per module, as in just the cargo
> inputs for zoxide in gnu/packages/rust-crates/zoxide.scm, and then you
> wouldn't need to worry about removing variables that aren't used by
> zoxide anymore but are used by another package?

I agree with Efraim here. My initial thoughts were to have one package per
module not only because its easier to do, but also because it avoids any
merge/rebase conflicts with other packages/patches.



Re: How to move forward about Rust? antioxidant, cargo2guix, etc.

2025-02-26 Thread Murilo
On Wed Feb 26, 2025 at 3:43 AM -03, Hilton Chain wrote:
> Time to try in your own channel!!!

I just did, it worked for helix. I'll be trying in some more rust packages in
the following days.

> * Package cargo-audio[1] and cargo-license[2] or similiar software, and write 
> a
>   step-by-step packaging workflow.

I like this idea of the step-by-step packaging and having perhaps a contribution
workflow specifically for rust in the manual, we could also have a section and
write some tips of some common problems people might encounter when packaging
rust apps (for example "what to do when the package has a git reference in
Cargo.toml?").

> * Package cargo-audio[1] and cargo-license[2]
>
> [1] https://github.com/rustsec/rustsec/tree/main/cargo-audit
> [2] https://github.com/onur/cargo-license

Attached is a package for cargo-license done with your implementation :)
(PS: Took me less than 1 minute to package from an empty module)
(define-module (saayix packages rust cargo-license)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (gnu packages rust)
  #:use-module (guix build-system cargo)
  #:use-module (guix download)
  #:use-module (guix gexp)
  #:use-module (guix git-download)
  #:use-module (guix packages)
  #:export (cargo-license))

;;;
;;; *-cargo-inputs and crates definitions
;;;
;;; This file is managed by ‘guix import’.  DO NOT add definitions manually.
;;;

(define cargo-license-cargo-inputs
  (delay (list rust-ansi-term-0.12.1
   rust-anstream-0.6.11
   rust-anstyle-1.0.4
   rust-anstyle-parse-0.2.3
   rust-anstyle-query-1.0.2
   rust-anstyle-wincon-3.0.2
   rust-anyhow-1.0.79
   rust-camino-1.1.6
   rust-cargo-platform-0.1.6
   rust-cargo-metadata-0.18.1
   rust-clap-4.4.18
   rust-clap-builder-4.4.18
   rust-clap-derive-4.4.7
   rust-clap-lex-0.6.0
   rust-colorchoice-1.0.0
   rust-csv-1.3.0
   rust-csv-core-0.1.11
   rust-either-1.9.0
   rust-equivalent-1.0.1
   rust-getopts-0.2.21
   rust-hashbrown-0.14.3
   rust-heck-0.4.1
   rust-indexmap-2.1.0
   rust-itertools-0.12.0
   rust-itoa-1.0.10
   rust-memchr-2.7.1
   rust-proc-macro2-1.0.78
   rust-quote-1.0.35
   rust-ryu-1.0.16
   rust-semver-1.0.21
   rust-serde-1.0.195
   rust-serde-derive-1.0.195
   rust-serde-json-1.0.111
   rust-serde-spanned-0.6.5
   rust-smallvec-1.13.1
   rust-spdx-0.10.3
   rust-strsim-0.10.0
   rust-syn-2.0.48
   rust-thiserror-1.0.56
   rust-thiserror-impl-1.0.56
   rust-toml-0.8.8
   rust-toml-datetime-0.6.5
   rust-toml-edit-0.21.0
   rust-unicode-ident-1.0.12
   rust-unicode-width-0.1.11
   rust-utf8parse-0.2.1
   rust-winapi-0.3.9
   rust-winapi-i686-pc-windows-gnu-0.4.0
   rust-winapi-x86-64-pc-windows-gnu-0.4.0
   rust-windows-sys-0.52.0
   rust-windows-targets-0.52.0
   rust-windows-aarch64-gnullvm-0.52.0
   rust-windows-aarch64-msvc-0.52.0
   rust-windows-i686-gnu-0.52.0
   rust-windows-i686-msvc-0.52.0
   rust-windows-x86-64-gnu-0.52.0
   rust-windows-x86-64-gnullvm-0.52.0
   rust-windows-x86-64-msvc-0.52.0
   rust-winnow-0.5.34)))
(define rust-ansi-term-0.12.1
  (let ((name "rust-ansi-term")
(version "0.12.1"))
(origin
  (method url-fetch)
  (uri (crate-uri "ansi_term" "0.12.1"))
  (file-name (string-append name "-" version ".tar.gz"))
  (sha256 (base32 
"1ljmkbilxgmhavxvxqa7qvm6f3fjggi7q2l3a72q9x0cxjvrnanm")
(define rust-anstream-0.6.11
  (let ((name "rust-anstream")
(version "0.6.11"))
(origin
  (method url-fetch)
  (uri (crate-uri "anstream" "0.6.11"))
  (file-name (string-append name "-" version ".tar.gz"))
  (sha256 (base32 
"19dndamalavhjwp4i74k8hdijcixb7gsfa6ycwyc1r8xn6y1wbkf")
(define rust-anstyle-1.0.4
  (let ((name "rust-anstyle")
(version "1.0.4"))
(origin
  (method url-fetch)
  (uri (crate-uri "anstyle" "1.0.4"))
  (file-name (string-append name "-" version ".tar.gz"))
  (sha256 (base32 
"11yxw02b6parn29s757z96rgiqbn8qy0fk9a3p3bhczm85dhfybh")
(define rust-anstyle-parse-0.2.3
  (let ((name "rust-anstyle-parse")
(version "0.2.3"))
(origin
  (method url-fetch)
  (uri (crate-uri "anstyle-parse" "0.2.3"))
  (file-name (string-append name "-" version ".tar.gz"))
  (sha256 (base32 
"134jhzrz89labrdwxxnjxqjdg06qvaflj1wkfnmyapwyldfwcnn7")
(define rust-anstyle-query-1.0.2
  (let (