Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

primops: add builtins.convertHash #7708

Merged
merged 8 commits into from Oct 19, 2023

Conversation

ShamrockLee
Copy link
Contributor

@ShamrockLee ShamrockLee commented Jan 29, 2023

Motivation

This PR adds a builtin function builtins.convertHash that converts a hash string to another format.

Context

Solves #3151
Cc: @nlewo

Examples:

# This returns "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
builtins.convertHash {
  hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
  toHashFormat = "sri";
  hashAlgo = "sha256";
}
# This returns "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
builtins.convertHash {
  hash = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
  toHashFormat = "base16";
}
# This returns "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
builtins.convertHash {
  hash = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
  toHashFormat = "sri";
}

Type:

builtins.convertHash :: { hash :: String, hashAlgo :: String, toHashFormat :: String } -> String
builtins.convertHash :: { hash :: String, toHashFormat :: String } -> String

To implement builtins.convertHash, the hash algorithm name (if specified) is parsed with parseHashType, and the hash format name with parseHashFormat. The original hash and the algorithm then feed to Hash::parseAny, and produce the result through its method to_string with the parsed hash format taken.

The attribute names are inspired by the outputHash, and outputHashAlgo used to specify FOD, and nix-hash --to-base*|--to-sri used to convert hash formats in the command line.

This PR also renames tree-wide from "hash base" to "hash format" to avoid confusion. This includes:

  • Rename enum Base to enum HashFormat.
  • Rename members of classes.
    • From CmdHashFormat::base to CmdHashFormat::hashFormat
    • From CmdToBase::base to CmdToBase::hashFormat
  • Rename temporary variables from hashBase or base to hashFormat.

Checklist for maintainers

Maintainers: tick if completed or explain if not relevant

  • agreed on idea
  • agreed on implementation strategy
  • tests, as appropriate
    • functional tests - tests/**.sh
    • unit tests - src/*/tests
    • integration tests - tests/nixos/*
  • documentation in the manual
  • code and comments are self-explanatory
  • commit message explains why the change was made
  • new feature or bug fix: updated release notes

@ShamrockLee ShamrockLee marked this pull request as ready for review January 29, 2023 14:18
@edolstra
Copy link
Member

This should probably be convertHash, since it's not very obvious what it means to "rebase" a hash.

"base" should probably be "encoding", since "sri" is not a base.

The type argument should not be mandatory, because SRI hashes already contain the type of the hash.

@ShamrockLee
Copy link
Contributor Author

Thanks for reviewing! convertHash sounds neet!

The type argument should not be mandatory, because SRI hashes already contain the type of the hash.

Regarding this, we could define convertSriHash that has the effect of convertHash type but without the type argument.

This could be done as a builtin (using either parseSRI or parseAnyPrefix in libutil/hash.cc) or inside Nixpkgs lib/strings.nix (by lib.splitString). Which one is preferred?

BTW, we would need to support colon-seperated hash prefix also, since "sha256:0000000000000000000000000000000000000000000000000000" is used by nix-prefetch.

@ShamrockLee
Copy link
Contributor Author

Just rename to convertHash, and add a new builtin convertSRIHash.

@ShamrockLee ShamrockLee changed the title primops: add builtins.rebaseHash primops: add builtins.convertHash and builtins.convertSRIHash Jan 30, 2023
@aameen-tulip
Copy link
Contributor

You're my hero.

@ShamrockLee
Copy link
Contributor Author

  1. Bump onto master
  2. Add release note
  3. Add tests

@ShamrockLee
Copy link
Contributor Author

Do you guys think I should rename convertSRIHash to convertSriHash or not?

@fricklerhandwerk fricklerhandwerk added feature Feature request or proposal language The Nix expression language; parser, interpreter, primops, evaluation, etc labels Mar 17, 2023
@ShamrockLee ShamrockLee force-pushed the primop-rebasehash branch 2 times, most recently from 8324e57 to 3114296 Compare May 25, 2023 15:19
@thufschmitt thufschmitt added the idea approved The given proposal has been discussed and approved by the Nix team. An implementation is welcome. label Jun 9, 2023
@roberth
Copy link
Member

roberth commented Jun 9, 2023

builtins.convertHash :: String -> String -> String -> String
builtins.convertSRIHash :: String -> String -> String

I think this should be changed to a single function where you can specify the output format, and perhaps optionally the input format. It should take an attribute set instead of positional arguments, to make clear which string is what.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-06-09-nix-team-meeting-minutes-61/29163/1

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/string-to-base-64/32624/2

@roberth roberth mentioned this pull request Sep 5, 2023
2 tasks
@ShamrockLee
Copy link
Contributor Author

ShamrockLee commented Sep 5, 2023

Sorry for late reply. I need some time to mourn for the catastrophic data loss on my laptop (~300 GiB disappeared after reboot) and restore the environment.

It should take an attribute set instead of positional arguments, to make clear which string is what.

What is the proper way to read in an attribute set for a built-in function? There seems to be a variety of implementation inside primops.cc.

Copy link
Contributor

@fricklerhandwerk fricklerhandwerk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ShamrockLee, I'll be available for getting this merged. I suggest to start with examples and usage notes for the docs, so we're sure the interface is smooth. Implementation is already largely there and should be straightforward.

src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libexpr/primops.cc Outdated Show resolved Hide resolved
doc/manual/src/release-notes/rl-next.md Outdated Show resolved Hide resolved
doc/manual/src/release-notes/rl-next.md Outdated Show resolved Hide resolved
@fricklerhandwerk
Copy link
Contributor

@ShamrockLee do you still have time to pursue this further? I'm really sorry that PRs here have such long turnaround times. We're working on improving that, step by step.

@ShamrockLee
Copy link
Contributor Author

ShamrockLee commented Oct 9, 2023

Another force push to clean up temporary files accidentally committed or remainings across rebase.

Copy link
Contributor

@fricklerhandwerk fricklerhandwerk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran the tests and played with it, it works. A few superficial items on documentation/presentation.

src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libutil/hash.hh Outdated Show resolved Hide resolved
src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libexpr/primops.cc Outdated Show resolved Hide resolved
@github-actions github-actions bot added new-cli Relating to the "nix" command store Issues and pull requests concerning the Nix store labels Oct 11, 2023
src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libexpr/primops.cc Outdated Show resolved Hide resolved
src/libutil/hash.hh Outdated Show resolved Hide resolved
Comment on lines +170 to +198
/**
* Parse a string representing a hash format.
*/
HashFormat parseHashFormat(std::string_view hashFormatName);

/**
* std::optional version of parseHashFormat that doesn't throw error.
*/
std::optional<HashFormat> parseHashFormatOpt(std::string_view hashFormatName);

/**
* The reverse of parseHashFormat.
*/
std::string_view printHashFormat(HashFormat hashFormat);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should have unit tests that they round-trip. Ideally also a rapidcheck property test too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round-trip test added.

I'm not familiar with rapidcheck property check. Are there examples of such tests? I'm still trying to figure out what https://github.com/emil-e/rapidcheck/blob/master/doc/properties.md would like to explain.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are examples of such tests, look at the store path tests.

@github-actions github-actions bot added the fetching Networking with the outside (non-Nix) world label Oct 18, 2023
ShamrockLee and others added 8 commits October 19, 2023 00:38
Remove redundant "else" after "return".

Use std::nullopt to increase readability.
List the allowed hash formats
hashBase is ambiguous, since it's not about the digital bases, but about
the format of hashes. Base16, Base32 and Base64 are all character maps
for binary encoding.

Rename the enum Base to HashFormat.

Rename variables of type HashFormat from [hash]Base to hashFormat,
including CmdHashBase::hashFormat and CmdToBase::hashFormat.
Add hash format analogy of
parseHashTypeOpt, parseHashType, and printHashType.

Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
@ShamrockLee
Copy link
Contributor Author

(Rebase to resolve merge conflict.)

@fricklerhandwerk
Copy link
Contributor

@ShamrockLee thank you very much for pulling through with this!

@fricklerhandwerk fricklerhandwerk merged commit 8b48fb1 into NixOS:master Oct 19, 2023
8 checks passed
@ShamrockLee ShamrockLee deleted the primop-rebasehash branch February 25, 2024 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request or proposal fetching Networking with the outside (non-Nix) world idea approved The given proposal has been discussed and approved by the Nix team. An implementation is welcome. language The Nix expression language; parser, interpreter, primops, evaluation, etc new-cli Relating to the "nix" command store Issues and pull requests concerning the Nix store with-tests Issues related to testing. PRs with tests have some priority
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

8 participants