3

I wrote a little command line tool, and want to add the "--help" usage message to the docs.

Since I am lazy, I would like to make the update procedure as simple as possible. Here is what I want to the update workflow to look like:

  1. Update code which results in an updates usage message.
  2. Run a script which updates the docs: The new usage message should be visible in the docs.

In other word: I don't want to copy+paste the usage message.

Step1 is comes from my own brain. But want to reuse existing tools for Step2.

Up to now the docs are just a simple README.rst file.

I would like to stick with a simple solution, where the docs can be visible directly via github. Up to now, I don't need the more complicated solution (like readthedocs).

How can I avoid copy+pasting the --help usage message?

Here is the tool I am working on: https://github.com/guettli/reprec

guettli
  • 25,042
  • 81
  • 346
  • 663
  • I'm not sure I understood properly: is generating `README.rst` programmatically from other manually edited files together with the `--help` output an option ? – bli Dec 04 '16 at 10:09
  • 1
    I am unsure about the "how", but I know what the result should look like. I want the output of `myprod --help` to be visible in the README. Automatically updating the README would be one solution. Doing some sort of including would be preferred, since I don't want automatic created text in git. I was told that all things which are created (like binary files from the compiler) should not be in git. – guettli Dec 05 '16 at 11:04
  • 1
    Maybe you should add this information in your question. Despite the general recommendation concerning git, I would have the README automatically re-created from two files (text before and text after the help) and the output of `myprod --help`, or some other equivalent setup (automatic substitution), and commit it together with your updates of `myprod`. You would have this README file under git anyway, so I guess the "don't track changes on automatically generated files" recommendation isn't really relevant here. – bli Dec 05 '16 at 12:30
  • I like what you're thinking. I'll whip something up. – pradyunsg Dec 07 '16 at 10:07
  • 1
    Is your primary aim to have your usage text visible in the README file on github? In which case you are kind of obliged to generate the text before you commit because while github can render RST it can't run arbitrary code such as you'd need to run your script and add it to the file. Have you considered using a [git pre-commit hook(https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) to generate your file if needed (using e.g. cog as suggested below) automatically on commit? – daphtdazz Dec 07 '16 at 15:47
  • @daphtdazz a git pre-commit hook. That's sounds good. Could you please write this as answer, since this fits quite good. Thank you. – guettli Dec 08 '16 at 06:25

4 Answers4

4

As suggested in the comments, you could use a git pre-commit hook to generate the README.rst file on commit. You could use an existing tool such as cog, or you could just do something very simple with bash.

For example, create a RST "template" file:

README.rst.tmpl

Test Git pre-commit hook project
--------------------------------

>>> INSERTION POINT FOR HELP OUTPUT <<<

.git/hooks/pre-commit

# Sensible to set -e to ensure we exit if anything fails
set -e

# Get the output from your tool.
# Paths are relative to the root of the repo
output=$(tools/my-cmd-line-tool --help)

cat README.rst.tmpl |
while read line
do
  if [[ $line == ">>> INSERTION POINT FOR HELP OUTPUT <<<" ]]
  then
    echo "$output"
  else
    echo "$line"
  fi
done > README.rst
git add README.rst

This gets run before you are prompted for a commit message, if you didn't pass one on the command line. So when the commit takes place if there were any changes to either README.rst.tmpl or the output from your tool, README.rst will be updated with it.

Edit

I believe this should work on Windows too, or something very similar, since git comes with a bash implementation on Windows, but I haven't tested it.

daphtdazz
  • 7,754
  • 34
  • 54
3

Consider using cog. It's meant for exactly this job.


Here's something that might just work. (untested) And... There's a lot of scope for improvement.

reprec
======

The tool reprec replaces strings in text files:

..  [[[cog
..      import cog
..  
..      def indent(text, width=4):
..          return "\n".join((" "*width + line) for line in text.splitlines())
..  
..      text = subprocess.check_output("reprec --help", shell=True)
..      cog.out("""
..  
..          ::
..  
..             ==> reprec --help""",
..          dedent=True
..      )
..      cog.out(indent(text))
..  ]]]

::

    ===> reprec --help
    <all-help-text>
..  [[[end]]]
pradyunsg
  • 18,287
  • 11
  • 43
  • 96
  • The tool `cog` looks like a simple template language (like jinia). Nice. Does github render cog, if I put [[[cog ...]]] into the README.rst file? – guettli Dec 07 '16 at 13:22
  • Cog is not a template language. From http://nedbatchelder.com/code/cog/, "Cog transforms files in a very simple way: it finds chunks of Python code embedded in them, executes the Python code, and inserts its output back into the original file. The file can contain whatever text you like around the Python code. It will usually be source code." -- Please go through about the linked page. – pradyunsg Dec 07 '16 at 13:39
  • Coming back to your question, No. Github does not render cog, the answer shows what you can change the section of the help to for using cog. – pradyunsg Dec 07 '16 at 13:40
1

For getting the usage text at Step 2, you can use the subprocess

usage_text = subprocess.check_output("reprec --help", shell=True)
otorrillas
  • 4,357
  • 1
  • 21
  • 34
1

I would actually approach in a quite different manner, from another side. I think the workflow you described may be greatly simplified if you switch to using argparse instead of getopt you use now. With this you will have:

  • I personally think, simpler code in your argument parsing function, and probably more safe, because argparse may verify a lot of conditions on given arguments, as long as you declare them (like data types, number of arguments, etc.)

  • and you can use argparse features to document the arguments directly in the code, right where you declare them (e.g.: help, usage, epilog and others); this effectively means that you could completely delete your own usage function, because argparse will handle this task for you (just run with --help to see the result).

To sum up, basically, arguments, their contracts and help documentation become mostly declarative, and managed altogether in one place only.


OK, OK, I know, the question originally stands how to update the README. I understand that your intention is to take the laziest approach. So, I think, it is lazy enough to:

  • maintain all your arguments and their documentation once in single place as above
  • then run something like myprograom --help > README.rst
  • commit ;)

OK, you will probably need something little bit more complex than just > README.rst. There we can go creative as we want, so the fun starts here. For example:

having README.template.rst (where you actually maintain the README content) and with ## Usage header somewhere in it:

$ myprogram --help > USAGE.rst
$ sed -e '/## Usage/r USAGE.rst' -e '$G' README.template.rst > README.rst

And you get everything working from same source code!

I think it will still need some polishing up, in order to generate valid rst document, but I hope it shows the idea in general.

Gist: Include generated help into README

Tim
  • 12,318
  • 7
  • 50
  • 72