logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

git-snail-mail.md (5576B)


  1. ---
  2. title: Announcing git snail-mail
  3. date: 2022-04-01
  4. ---
  5. > You've heard of git-over-email thanks to [git send-email][0] — now you
  6. > can enjoy *git snail-mail*: a new tool making it easier than ever to print out
  7. > git commits on paper and mail them to your maintainers.
  8. >
  9. > Running `git snail-mail HEAD~2..` prepares the last two commits for post and
  10. > sends them directly to the system's default printer. Configuration options are
  11. > available for changing printer settings, paper size, and options for faxing or
  12. > printing envelopes automatically addressed to the maintainers based on address
  13. > info stored in your git config. Be sure to help the maintainers review your
  14. > work by including a return envelope and a stamp!
  15. >
  16. > And for maintainers, code review has never been easier — just get out
  17. > your red marker and write your feedback directly on the patch! When you're
  18. > ready to import the patch into your repository, just place it on your scanner
  19. > and run `git scan-mail`.
  20. [0]: https://git-send-email.io
  21. ![A picture of a patch printed out on paper](https://l.sr.ht/w9hP.jpg)
  22. At least, this is what I'd like to say, but I ended up cancelling the project
  23. before it was ready for April Fool's. After my friend kline (a staffer at Libera
  24. Chat) came up with this idea, I actually did write a lot of the code! Git is
  25. mostly written in Perl, but I could not really rouse the enthusiasm for
  26. implementing this idea in Perl. I did the prototype in $secretlang instead, and
  27. got it mostly working, but decided not to try to do some sneaky half-private
  28. joke release while trying to maintain the secrecy of the language.
  29. Essentially how it works is this: I have a TeX template for patches:
  30. ```tex
  31. \documentclass{article}
  32. \usepackage[
  33. a4paper,
  34. top=1cm,
  35. bottom=1cm,
  36. left=1cm,
  37. right=1cm,
  38. ]{geometry}
  39. \usepackage{graphicx}
  40. \usepackage{fancyvrb}
  41. \pagenumbering{gobble}
  42. \begin{document}
  43. \section*{implement os::exec::peek\{,any\}}
  44. From: Bor Grošelj Simić \textless{}bor.groseljsimic@telemach.net\textgreater{} \\
  45. Date: Fri, 25 Feb 2022 01:46:13 +0100
  46. \VerbatimInput{input.patch}
  47. \newpage
  48. Page 1 of 2 \\
  49. \includegraphics[]{./output-1.png}
  50. \newpage
  51. Page 2 of 2 \\
  52. \includegraphics[]{./output-2.png}
  53. \end{document}
  54. ```
  55. This is generated by my git snail-mail code and then run through pdflatex to
  56. produce a file [like this][1]. It pipes it into lp(1) to send it to your printer
  57. and ta-da!
  58. [1]: https://l.sr.ht/2VXT.pdf
  59. I chose not to make the commit selection work like git send-email, because I
  60. think that's one of the most confusing parts of git send-email. Instead I just
  61. use a standard revision selection, so to print a single commit, you just name
  62. it, and to print a range of commits you use "..". Here's a peek at how that
  63. works:
  64. ```hare
  65. fn get_commits(
  66. data: *texdata,
  67. workdir: str,
  68. range: str,
  69. ) (void | exec::error | exec::exit_status | io::error | fs::error) = {
  70. const fmt = `--format=%H%x00%s%x00%aN%x00%aE%x00%aD`;
  71. const pipe = exec::pipe();
  72. const cmd = exec::cmd("git", "show", "-s", fmt, range)?;
  73. exec::addfile(&cmd, os::stdout_file, pipe.1);
  74. const proc = exec::start(&cmd)?;
  75. io::close(pipe.1);
  76. const pipe = pipe.0;
  77. defer io::close(pipe);
  78. static let buffer: [os::BUFSIZ]u8 = [0...];
  79. const pipe = &bufio::buffered(pipe, buffer[..], []);
  80. let path = path::init();
  81. for (true) {
  82. const line = match (bufio::scanline(pipe)?) {
  83. case let line: []u8 =>
  84. yield strings::fromutf8(line);
  85. case io::EOF =>
  86. break;
  87. };
  88. // XXX: This assumes git always does the thing
  89. const tok = strings::tokenize(line, "\0");
  90. let commit = commitdata {
  91. sha = strings::next_token(&tok) as str,
  92. subject = strings::next_token(&tok) as str,
  93. author = strings::next_token(&tok) as str,
  94. email = strings::next_token(&tok) as str,
  95. date = strings::next_token(&tok) as str,
  96. ...
  97. };
  98. path::set(&path, workdir)!;
  99. path::add(&path, commit.sha)!;
  100. commit.diff = strings::dup(path::string(&path));
  101. append(data.commits, commit);
  102. const file = os::create(commit.diff, 0o644)?;
  103. defer io::close(file);
  104. const parent = strings::concat(commit.sha, "^");
  105. defer free(parent);
  106. const cmd = exec::cmd("git", "diff", parent, commit.sha)?;
  107. exec::addfile(&cmd, os::stdout_file, file);
  108. const proc = exec::start(&cmd)?;
  109. const status = exec::wait(&proc)?;
  110. exec::check(&status)?;
  111. };
  112. const status = exec::wait(&proc)?;
  113. exec::check(&status)?;
  114. };
  115. ```
  116. The `--format` argument provided to git at the start here allows me to change
  117. the format of git-show to use NUL delimited fields for easily picking out the
  118. data I want. Point of note: this is minimum-effort coding for a joke, so there's
  119. a lot of missing error handling and other lazy design choices here.
  120. Anyway, I would have liked to have rewritten this in Perl and pitched it to the
  121. git mailing list for inclusion upstream, but alas, after prototyping in
  122. $secretlang I could not bring myself to rewrite it in Perl, and the joke fell
  123. flat. Not every idea pans out, but they're still worth trying, anyway. If you
  124. want to see some joke projects I've made that actually work, check these out:
  125. - [shit](https://git.sr.ht/~sircmpwn/shit): a git implementation in POSIX shell
  126. - [bfbot](https://git.sr.ht/~sircmpwn/bfbot): a working IRC bot written in brainfuck
  127. - [classic6](https://git.sr.ht/~sircmpwn/classic6): a working Minecraft server written in 6 hours
  128. - [evilpass](https://git.sr.ht/~sircmpwn/evilpass): a password strength checker that detects password reuse
  129. - [tw](https://git.sr.ht/~sircmpwn/tw): a Wayland compositor for your terminal in 80 lines of "code"
  130. Take care!