logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git
commit: 472a2c5cacd94cca670e95a07231395290c6a606
parent d671179e9780dc434de49d0ccfaa06ae53bfeffa
Author: Drew DeVault <sir@cmpwn.com>
Date:   Fri,  1 Apr 2022 11:14:06 +0200

git snail-mail

Diffstat:

Acontent/blog/git-snail-mail.md160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 160 insertions(+), 0 deletions(-)

diff --git a/content/blog/git-snail-mail.md b/content/blog/git-snail-mail.md @@ -0,0 +1,160 @@ +--- +title: Announcing git snail-mail +date: 2022-04-01 +--- + +> You've heard of git-over-email thanks to [git send-email][0] &mdash; now you +> can enjoy *git snail-mail*: a new tool making it easier than ever to print out +> git commits on paper and mail them to your maintainers. +> +> Running `git snail-mail HEAD~2..` prepares the last two commits for post and +> sends them directly to the system's default printer. Configuration options are +> available for changing printer settings, paper size, and options for faxing or +> printing envelopes automatically addressed to the maintainers based on address +> info stored in your git config. Be sure to help the maintainers review your +> work by including a return envelope and a stamp! +> +> And for maintainers, code review has never been easier &mdash; just get out +> your red marker and write your feedback directly on the patch! When you're +> ready to import the patch into your repository, just place it on your scanner +> and run `git scan-mail`. + +[0]: https://git-send-email.io + +![A picture of a patch printed out on paper](https://l.sr.ht/w9hP.jpg) + +At least, this is what I'd like to say, but I ended up cancelling the project +before it was ready for April Fool's. I did actually write a lot of the code for +this idea! Git is mostly written in Perl, but I could not really rouse the +enthusiasm for implementing this idea in Perl. I did the prototype in +$secretlang instead, and got it mostly working, but decided not to try to do +some sneaky half-private joke release while trying to maintain the secrecy of +the language. + +Essentially how it works is this: I have a TeX template for patches: + +```tex +\documentclass{article} +\usepackage[ + a4paper, + top=1cm, + bottom=1cm, + left=1cm, + right=1cm, +]{geometry} +\usepackage{graphicx} +\usepackage{fancyvrb} +\pagenumbering{gobble} + +\begin{document} + +\section*{implement os::exec::peek\{,any\}} + +From: Bor Grošelj Simić \textless{}bor.groseljsimic@telemach.net\textgreater{} \\ +Date: Fri, 25 Feb 2022 01:46:13 +0100 + +\VerbatimInput{input.patch} + +\newpage +Page 1 of 2 \\ +\includegraphics[]{./output-1.png} + +\newpage +Page 2 of 2 \\ +\includegraphics[]{./output-2.png} + +\end{document} +``` + +This is generated by my git snail-mail code and then run through pdflatex to +produce a file [like this][1]. It pipes it into lp(1) to send it to your printer +and ta-da! + +[1]: https://l.sr.ht/2VXT.pdf + +I chose not to make the commit selection work like git send-email, because I +think that's one of the most confusing parts of git send-email. Instead I just +use a standard revision selection, so to print a single commit, you just name +it, and to print a range of commits you use "..". Here's a peek at how that +works: + +```hare +fn get_commits( + data: *texdata, + workdir: str, + range: str, +) (void | exec::error | exec::exit_status | io::error | fs::error) = { + const fmt = `--format=%H%x00%s%x00%aN%x00%aE%x00%aD`; + + const pipe = exec::pipe(); + const cmd = exec::cmd("git", "show", "-s", fmt, range)?; + exec::addfile(&cmd, os::stdout_file, pipe.1); + const proc = exec::start(&cmd)?; + io::close(pipe.1); + const pipe = pipe.0; + defer io::close(pipe); + + static let buffer: [os::BUFSIZ]u8 = [0...]; + const pipe = &bufio::buffered(pipe, buffer[..], []); + + let path = path::init(); + + for (true) { + const line = match (bufio::scanline(pipe)?) { + case let line: []u8 => + yield strings::fromutf8(line); + case io::EOF => + break; + }; + + // XXX: This assumes git always does the thing + const tok = strings::tokenize(line, "\0"); + let commit = commitdata { + sha = strings::next_token(&tok) as str, + subject = strings::next_token(&tok) as str, + author = strings::next_token(&tok) as str, + email = strings::next_token(&tok) as str, + date = strings::next_token(&tok) as str, + ... + }; + + path::set(&path, workdir)!; + path::add(&path, commit.sha)!; + commit.diff = strings::dup(path::string(&path)); + append(data.commits, commit); + + const file = os::create(commit.diff, 0o644)?; + defer io::close(file); + const parent = strings::concat(commit.sha, "^"); + defer free(parent); + + const cmd = exec::cmd("git", "diff", parent, commit.sha)?; + exec::addfile(&cmd, os::stdout_file, file); + const proc = exec::start(&cmd)?; + const status = exec::wait(&proc)?; + exec::check(&status)?; + }; + + const status = exec::wait(&proc)?; + exec::check(&status)?; +}; +``` + +The `--format` argument provided to git at the start here allows me to change +the format of git-show to use NUL delimited fields for easily picking out the +data I want. Point of note: this is minimum-effort coding for a joke, so there's +a lot of missing error handling and other lazy design choices here. + +Anyway, I would have liked to have rewritten this in Perl and pitched it to the +git mailing list for inclusion upstream, but alas, after prototyping in +$secretlang I could not bring myself to rewrite it in Perl, and the joke fell +flat. Not every idea pans out, but they're still worth trying, anyway. If you +want to see some joke projects I've made that actually work, check these out: + +- [shit](https://git.sr.ht/~sircmpwn/shit): a git implementation in POSIX shell +- [bfbot](https://git.sr.ht/~sircmpwn/bfbot): a working IRC bot written in brainfuck +- [classic6](https://git.sr.ht/~sircmpwn/classic6): a working Minecraft server written in 6 hours +- [evilpass](https://git.sr.ht/~sircmpwn/evilpass): a password strength checker that detects password reuse +- [tw](https://git.sr.ht/~sircmpwn/tw): a Wayland compositor for your terminal in 80 lines of "code" + +Take care!