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

add default.nix which can produce ps and pdf files #52

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

apoelstra
Copy link
Contributor

Will also patch the git commit into the "revision" variable which appears in the ps output, if told to build a git repo rather than the current source tree.

default.nix Outdated Show resolved Hide resolved
'';
};
in
stdenv.mkDerivation {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not just put renderBooklet as the derivation result? Wouldn't that make it easier to check the result into git? We can do nix-build -o SSS32.ps and then commit SSS32.ps. (I haven't actually tried this).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I eventually want to produce more than one output -- the full booklet, but also postscript files with individual worksheets, 256-bit vesrions of the worksheets, etc. And maybe a illustrated version alongside the regular version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On further reflection, and having learned Nix better, let me explore making this derivation have multiple outputs, where the default is the fully-assembled SSS32.ps. I'm unsure if this is the right way to go still, because there are e.g. flags we want to be able to set about PDF vs PS, color vs non-color etc, and it might still be the cleanest thing to output a directory with a bunch of different files.

Copy link
Collaborator

Choose a reason for hiding this comment

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

My experiments with git and symlinks was a failure. While we could support multiple outputs, I do not think that it worth worrying about. At least not at this time.

@apoelstra apoelstra force-pushed the 2023-03--nixify branch 2 times, most recently from d6cf782 to 865b397 Compare March 20, 2023 21:44
@apoelstra
Copy link
Contributor Author

Force pushed to a .nix which more closely matches the file I'm actually working with to add the full booklet contents, color, etc.

You can see how the dependency management is going to work, once we break up the setup code into more than a single file, and we output the full booklet, but it's hopefully clearer how we'd output other documents too.

@roconnor-blockstream
Copy link
Collaborator

9946318 seems to add an extra blank line on line 2060 for no good reason.

default.nix Outdated
exit 1
fi
}
'' + lib.optionalString doPageChecks toString (
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this all be in a standard checkPhase gated by a standard doCheck flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, yes, it should be.

shortId = lib.optionalString (! isNull ref) ("-" + builtins.substring 0 8 src.rev);


setup = rec {
Copy link
Collaborator

Choose a reason for hiding this comment

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

probably best to remove rec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can remove it for now, but it will be used -- this setup set will contain all the various components of the postscript "setup" section. Each will have a dependencies array which refers to other setup components.

default.nix Outdated
${lib.optionalString (pageData ? drawPageContent) "end\n"}pgsave restore
showpage
'';
nextCtIdx = content.nextCtIdx + (if pageData ? drawPageContent then 1 else 0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should CtIdx just be PgIdx - 1, or is that just a coincidence?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just a coincidence, but let me check my current development branch to see if we want this calculation at all. It originates with the PostScript originally having a giant array of page content in the setup section, but now that we're assembling pages in Nix, I'm going to move the content into their respective pages rather than indexing into an array.

Regarding the page numbering logic, it's going to wind up being a little ugly, since we need to support

  • Pages that get numbers
  • Pages that are numbered, but the number isn't displayed because it'd interfere with the content (at least one volvelle page are like this)
  • Pages that aren't numbered at all

I'd also like to support some preamble pages having numbers like i, ii, iii, etc.

Anyway for now maybe I just want to rip out the page numbering logic entirely since we need to iterate on it.

@apoelstra
Copy link
Contributor Author

apoelstra commented Apr 7, 2023

@roconnor-blockstream I'll check on the "no good reason" blank line while in flight today, but I suspect that it's there because Nix multiline strings always end in a newline (or is it that they start with a newline? I forget), so if we don't have these newlines in the target output, it forces you to cram lots of stuff onto single lines.

Edit no, this one was indeed for "no good reason" :) I'll remove it.

@apoelstra
Copy link
Contributor Author

@roconnor-blockstream pushed new version which

  • Renames nextCtIdx to nextFooterIdx to match my local "complete" branch and to reflect that this value indicates the page number to be drawn in the footer, not an index into any content
  • Removes the extraneous blank line :)
  • Splits the page tests and diff into a checkPhase section and added a doCheck flag
  • Minor refactorings

%*
%****************************************************************
'' + ''
%%Page: ${toString content.nextPgIdx} ${toString content.nextPgIdx}
Copy link
Collaborator

@roconnor-blockstream roconnor-blockstream Apr 8, 2023

Choose a reason for hiding this comment

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

Perhaps this is for a follow up PR, but if you want to get fancy with page numbering then you need to update this line. This isn't just a pair of page numbers repeated for no reason. You'll have to look up the spec, but it is something like one is the literal sequence number and the other is the displayed page number. This makes a difference for assembling a sidebar of contents on your PS viewer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@roconnor-blockstream yep, I'll address that in a future PR. Unfortunately ps2pdf loses this information (or maybe PDF doesn't support it) so it's of somewhat limited value.

default.nix Outdated

mkdir "$out"
cd "$out"
cp ${renderBooklet fullBooklet} SSS32.ps
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be a symlink instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, yeah, I guess it could be. It didn't occur to me.

cp ${renderBooklet fullBooklet} SSS32.ps

${lib.optionalString doOutputDiff "diff -C 5 ${src}/SSS32.ps SSS32.ps"}
sed -i 's/(revision \(.*\))/(revision \1${shortId})/' ./SSS32.ps
Copy link
Collaborator

Choose a reason for hiding this comment

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

This probably needs to be more robust, but it is fine for now.

default.nix Outdated
stdenv.mkDerivation {
name = "codex32${shortId}";

buildInputs = if doPdfGeneration then [ ghostscript ] else [ ];
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this ought to be nativeBuildInputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, will change. I really don't understand the distinction.

Copy link
Collaborator

@roconnor-blockstream roconnor-blockstream Jul 25, 2023

Choose a reason for hiding this comment

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

My vague understanding is that buildInputs is historic, and means build and runtime dependencies. While nativeBuildInputs is just build time dependencies. I'm not sure what the actual effect of this difference is.

default.nix Outdated
buildPhase = ''
set -e

ghostscriptTest() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would make more sense inside checkPhase.

@apoelstra
Copy link
Contributor Author

Rebased to address commetns.

default.nix Outdated
# Copy output Postscript into place
mkdir "$out"
cd "$out"
ln -s "$FULL_BW" SSS32.ps
Copy link
Collaborator

Choose a reason for hiding this comment

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

You changed this from cp to ln -s, but below you patch the file with sed. Does this even work? the content of FULL_BW should be an immutable nix-store file, so I don't think you can patch it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should renderBooklet take a revision argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it does not work. The sed line appears to be doing nothing, and since it does nothing, does not even try to write to the file, and returns success.

As for "should renderBooklet just take a revision argument?" let me investigate that. Would be more elegant than rendering the book and then patching it after-the-fact, but might make templating a bit weird.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After testing this by setting the ref parameter, I believe the existing code does work. I am investigating how. It's as though the ln -s is doing a copy-on-write copy rather than a softlink. (I can confirm that the target file is modified by sed but the original file is not.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, sed -i will replace linked files unless you pass it --follow-symlinks.

Linux.

@apoelstra apoelstra marked this pull request as draft May 6, 2024 14:24
@apoelstra
Copy link
Contributor Author

Will undraft when this is ready for review again. Hopefully today or tomorrow.

Pretty-much just adds and removes some newlines in preparation for
nix-generating the main PostScript file's page numbering.
@apoelstra
Copy link
Contributor Author

Restored the old cp line rather than using ln -s and relying on sed's magic link-replacing behavior.

Added Makefile which figures out the git commit ID and passes it to nix.

@apoelstra apoelstra marked this pull request as ready for review May 10, 2024 21:20
@VzxPLnHqr
Copy link

VzxPLnHqr commented May 14, 2024

@roconnor-blockstream @apoelstra
Apologies to barge in on this PR, but it seemed the most relevant location given that you are nixifying codex32 things here and that would be immensely helpful.

I have a (currently failed) attempt to add apoelstra/volvelle-website to nixos-airgapped. My attempt is failed currently because there is some sort of permission error when trying to run wasm-pack and my rust/nix skills are not the greatest yet. You may be able to diagnose in 30 seconds and it would be greatly appreciated!

Also, is that volvelle-website repo even the correct one to be doing this with? I noticed that this repo seems to have more activity. Do you intend to add some sort of nix build .#codex32-offline-website magic to this repo that builds the static website?

@apoelstra
Copy link
Contributor Author

You may be able to diagnose in 30 seconds and it would be greatly appreciated!

Afraid not. I just checked my local nix CI scripts to see if I got wasm-pack working, and the answer is no, I only have wasm-pack code in one place, and it's all commented out with a confusing explanation. Unfortunately wasm-pack is a nightmare to use in an airgapped context, because it downloads random crapand does not respect lockfiles.

Also, is that volvelle-website repo even the correct one to be doing this with? I noticed that this repo seems to have more activity.

Yeah, this repo is where the "real" work is happening. The website is more-or-less a demo and an aid for doing workshops. (I think I will do one in October at TABconf so probably you'll see a bunch of activity there in the week(s) leading up to that, and nothing until then.)

But you raise an interesting point that we should have a self-contained "codex32 tool" that people can build and use locally. WASM is nice because you can run it in the browser and easily have nice interactive interfaces, but it's pretty awful in every other respect.

One soluion for you would be to just build the site and nix-package the binary output....that'd fly in Nix land even though it wouldn't fly in Guix. But I definitely understand if you refuse on principle to do that!

Do you intend to add some sort of nix build .#codex32-offline-website magic to this repo that builds the static website?

Probably not, unless we can get away from wasm-pack. (Which honestly shouldn't be too hard ... in theory I just need to run cargo with a wasm32-unknown-unknown target and then write a tiny bit of glue code ... but I don't know how.)

@VzxPLnHqr
Copy link

...see if I got wasm-pack working, and the answer is no... Unfortunately wasm-pack is a nightmare

Thanks for your reply and suggestions. It does give me some comfort that it was not just me who was unable to figure out the wasm-pack stuff with nix!

Regarding a self-contained "codex32 tool," agree that would be helpful.

@VzxPLnHqr
Copy link

I opened a PR to the website repo with a flake such that nix build .#codex32-website will put a static copy of the website in ./results/www.

@BenWestgate
Copy link
Contributor

...see if I got wasm-pack working, and the answer is no... Unfortunately wasm-pack is a nightmare

Thanks for your reply and suggestions. It does give me some comfort that it was not just me who was unable to figure out the wasm-pack stuff with nix!

Regarding a self-contained "codex32 tool," agree that would be helpful.

@VzxPLnHqr: What features are you expecting a self-contained "codex32 tool" to have? I may have already made one.

@VzxPLnHqr
Copy link

What features are you expecting a self-contained "codex32 tool" to have? I may have already made one.

@BenWestgate I have not played with it too much yet, so maybe a self-hosted / static version of the website will suffice? (such as as what I added to nixos-airgapped ). But a simple command line interface could be nice too. Is that what you have made already?

@BenWestgate
Copy link
Contributor

What features are you expecting a self-contained "codex32 tool" to have? I may have already made one.

@BenWestgate I have not played with it too much yet, so maybe a self-hosted / static version of the website will suffice? (such as as what I added to nixos-airgapped ). But a simple command line interface could be nice too. Is that what you have made already?

Yes, https://github.com/BenWestgate/codex32/blob/master/reference/python-codex32/src/codex32.py has functions for all sorts of codex32 needs.

I started working on a Gtk GUI for importing with error correction: https://github.com/BenWestgate/bails-wallet/blob/master/bails-wallet/string_entry.py I think it was meeting most or all of the criteria of https://github.com/BlockstreamResearch/codex32/blob/master/docs/wallets.md when I last tested it.

These were originally for my project https://github.com/BenWestgate/Bails which uses the python library above to support creating codex32 backups and importing them to Bitcoin core. If andrew's bitcoin/bitcoin future PR bitcoin/bitcoin#27351 (comment) gets merged most of that code except my GUI and error correction can be deleted.

@roconnor-blockstream
Copy link
Collaborator

Page: 1 1 seems to now have portraitPage begin twice. Presumably this is an error

@apoelstra
Copy link
Contributor Author

Oh, good catch. This appears in title.inc.ps but shouldn't because the default.nix code now does it.

@apoelstra
Copy link
Contributor Author

Fixed.

else
fetchGit {
url = ./.;
inherit ref;
Copy link
Collaborator

Choose a reason for hiding this comment

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

After reviewing https://nix.dev/manual/nix/2.22/language/builtins#builtins-fetchGit I'm pretty sure you want rev instead of ref.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Empirically rev seems to want a 40-character hash, while ref will accept short hashes, branch names, etc.

@roconnor-blockstream
Copy link
Collaborator

Oh, good catch. This appears in title.inc.ps but shouldn't because the default.nix code now does it.

Maybe I'm being too picky, but you patched the wrong commit. You should have put the title.inc.ps patch in add version to footer; use portraitPage and landscapePage on every page. However instead you patched nix: generate postscript file from include files.

nix: generate postscript file from include files was supposed to be a nop with regards to the SSSS32.ps file, but now that files has a diff in it, a diff that gets reversed again in add version to footer; use portraitPage and landscapePage on every page.

@apoelstra
Copy link
Contributor Author

I don't think you're being too picky. Though I'm surprised I made a mistake like that, given that I used git blame to zero in on what I thought was the correct commit, and then ran nix-build on every subsequent commit which showed that the SSSS32.ps file was consistent with the nixfile.

I'll fix the history. Sorry about that.

apoelstra added 4 commits June 4, 2024 23:12
Generates the committed postscript and runs diff to make sure that the
reconstruction was faithful. Currently this simply reproduces the
existing code, though it autogenerates the numbers to make it easier
to rearrange things and/or add blank pages.

Later PRs will abstract out the setup code, improve best practices (e.g.
wrapping every page in "10 dict ... end") and add additional targets
which produce e.g. individual worksheets in their own postscript.

We will also use the Nix mechanism to add illustrations, rather than
using PHP.
@apoelstra
Copy link
Contributor Author

Ah, I see the issue. I was misled by git blame (or perhaps, misled by my weird PR structure where I introduced code intending to later modify it).

Fixed.

@roconnor-blockstream
Copy link
Collaborator

Are you familiar with gitattributes's export-subst?

Bitcoin uses this to insert a define GIT_COMMIT_ID into this file. This method might make for a better way adding shortids to the (generated) postscript.

@apoelstra
Copy link
Contributor Author

No, I am not familiar -- though it looks like it needs git-archive to work. I am averse to using git-archive, especially the way Bitcoin Core does, because it interacts with nix in unpredictable ways. (For example in rust-bitcoinconsensus when I try to verify that the vendored Core code matches the relevant Core commit, I have a giant list of whitelisted files which seem to be .gitignored in one case but not in the other, and files which always have diffs that I can't reproduce locally, presumably because they are done by git attributes.)

I can go learn all these things if you want but I feel that my existing way, which behaves predictably and uses explicit code, will be easier to maintain.


nativeBuildInputs = if doPdfGeneration then [ ghostscript ] else [ ];

phases = [ "buildPhase" ] ++ lib.optionals doCheck [ "checkPhase" ];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unfortunately the checkPhase is never run because doCheck needs to be set to true in the stdenv.mkDerivation in order to run the checkPhase

You should change the phases line to:

phases = [ "buildPhase" "checkPhase" ];
inherit doCheck;

and let doCheck control whether or not the check phase is executed or not.

${lib.optionalString doPdfGeneration "ps2pdf -dPDFSETTINGS=/prepress SSS32.ps"}
'';

checkPhase = toString
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unfortunately the check fails when it is actually enabled, at least in part because you try to run ghostscriptTest before it is defined.


checkPhase = toString
(map
(page: "ghostscriptTest ${checkSinglePage page}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is another issue with this design. Because checkPhase contains references to the single pages, those single pages must be built, whether or not they will be checked. In this case I suggest taking the unusual step of conditionally excluding the entire contents of the checkPhase value if doCheck is false.

Alternatively you could replace fullBooklet.pages with [] when doCheck is false.

buildPhase = ''
set -e

FULL_BW="${renderBooklet fullBooklet}"
Copy link
Collaborator

Choose a reason for hiding this comment

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

The way nix derivations work is that, more or less, every value in the derivation becomes an environment variable.

Therefore, it would make more sense for you to define FULL_BW as an entry in the derivation rather that setting it in the build phase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants