rogpeppe / go-internal

Selected Go-internal packages factored out from the standard library
BSD 3-Clause "New" or "Revised" License
825 stars 67 forks source link

txtar-c: add -script flag #181

Open bitfield opened 1 year ago

bitfield commented 1 year ago

TL;DR have txtar-c include an optional test script in the archive it creates.

Use case

Suppose we want to use the marvellous testscript runner to run a given script against a set of files. For example, we might want to test a directory containing Go files using some script test.txtar:

exec go test

Of course, we can't run this script as it stands, because it doesn't contain the Go files. So, how to add them?

We could create a txtar archive of the directory using txtar-c, concatenate the result with our original script, and run the result of that with testscript. This is straightforward:

cp test.txtar archive.txtar
txtar-c $DIR >>archive.txtar
testscript archive.txtar
rm archive.txtar

Unfortunately, if DIR has files containing txtar file marker lines, this produces the wrong result. txtar-c -quote prepends the necessary unquote lines to its archive:

unquote expect
-- expect --
> -- input.txt --
> hello world

Simple-mindedly prepending our test.txtar script to this would produce:

exec go test
unquote expect
... 

That's no good, because presumably we need the files to be unquoted before running go test. So the script needs to go after any unquote lines, but before the file data. This is not straightforward, and this shell script is unsatisfactory for any number of reasons (bonus points if you spot all twelve):

txtar-c -quote $DIR >archive.tmp
# First, extract the leading 'unquote' lines
grep unquote archive.tmp >archive.txtar
# Next, append the script lines
cat test.txtar >>archive.txtar
# Finally, append the remaining file data
grep -v 'unquote' archive.tmp >>archive.txtar
testscript archive.txtar
rm archive.tmp archive.txtar

How much nicer it would be if we could simply ask txtar-c to include our script file in the appropriate place!

txtar-c -script test.txtar -quote $DIR | testscript

This makes it very easy and pleasant to use testscript to run scripts against some existing set of files, for example in a CI pipeline. A decent value-add for eight extra lines of code, I think.

mvdan commented 1 year ago

I should also mention that https://pkg.go.dev/golang.org/x/exp/cmd/txtar exists now, alongside https://pkg.go.dev/golang.org/x/tools/txtar. It already supports comments via stdout when extracting, and stdin when archiving. It doesn't appear to do any form of sanity checking on the input, so I guess we could do the same.

I agree with Roger though - this tool should not be aware of testscript at all.