1cde3753607e — Steve Fink 2 months ago
[run-taskcluster-job] Spent way too much time futzing with help message
1 files changed, 81 insertions(+), 13 deletions(-)

M bin/run-taskcluster-job
M bin/run-taskcluster-job +81 -13
@@ 9,23 9,87 @@ import subprocess
 import shlex
 import sys
 
-# TODO:
-# [ ] Uh... figure out the workflow with --image or whatever. Right now, it creates a
-#     new container without the env file!
-
 DEFAULT_ENV_FILE = "/tmp/task_env.sh"
 DEFAULT_IMAGE = "docker.io/library/debian10-amd64-build:latest"
 
-parser = argparse.ArgumentParser("run a taskcluster image")
-parser.add_argument("--log-task-id", help="The task you are trying to replicate. Its log file will be scanned for the task ID that provided the base image to run.")
-parser.add_argument("--load-task-id", help="The toolchain task that generated the image to use. This will be passed to `mach load-taskcluster-image`.")
-parser.add_argument("--task-id", help="The task you are trying to replicate. Use this instead of --log-task-id if you have already pulled down the image.")
+
+class HelpFormatter(argparse.HelpFormatter):
+    '''Formatter class that preserves blank lines but still allows reflowing'''
+    def _fill_text(self, text, width, indent):
+        if not text.startswith('[keep-blank-lines]'):
+            return super()._fill_text(text, width, indent)
+
+        text = text.replace('[keep-blank-lines]', '').lstrip()
+
+        chunks = [[]]
+        for raw in text.splitlines():
+            if raw == '':
+                chunks.append([])
+            else:
+                chunks[-1].append(raw)
+
+        formatted = ''
+        for chunk in chunks:
+            import textwrap
+            formatted += textwrap.fill(
+                ' '.join(chunk),
+                width,
+                initial_indent=indent,
+                subsequent_indent=indent
+            ) + "\n\n"
+        return formatted
+
+
+parser = argparse.ArgumentParser(
+    description='Run a taskcluster job in a local docker container.',
+    epilog='''[keep-blank-lines]
+Basic usage is to pass --log-task-id with the task ID that you are trying to
+replicate. But you will probably end up wanting to re-run it, and perhaps
+mount your Gecko checkout into the container instead of checking out one
+from scratch (which is slow and burns lots of disk space).
+
+For re-running, you can use --container (with no argument) and it will present
+a list of available containers. Hopefully you have few enough that you can tell
+which one it is!
+
+For mounting your gecko checkout, pass
+
+    --mount /home/me/gecko=/builds/worker/checkouts/gecko
+
+and note that this will remove the `--gecko-checkout=...` portion of $COMMAND.
+
+Once you have a shell running within the container, you may use $COMMAND
+to run the task. You may want to set
+
+    MOZ_FETCHES='[]'
+
+after the first run to avoid re-fetching lots of dependencies.''',
+    formatter_class=HelpFormatter,
+)
+
+parser.add_argument("--log-task-id", metavar='TASK_ID',
+                    help="The task you are trying to replicate. Its log file "
+                    "will be scanned for the task ID that provided the base "
+                    "image to run.")
+parser.add_argument("--load-task-id", metavar='TASK_ID',
+                    help="The toolchain task that generated the image to use. "
+                    "This will be passed to `mach load-taskcluster-image`.")
+parser.add_argument("--task-id",
+                    help="The task you are trying to replicate. Use this "
+                    "instead of --log-task-id if you have already pulled "
+                    "down the image.")
 parser.add_argument("--image", nargs="?", const="infer", default=None,
-                    help="The image to create a new docker container out of, omit IMAGE to select from available")
+                    help="The image to create a new docker container out of, "
+                    "omit IMAGE to select from available")
 parser.add_argument("--container", nargs="?", const="infer", default=None,
-                    help="An existing container to run a shell in, omit CONTAINER to select from available")
-parser.add_argument("--env-file")
-parser.add_argument("--mount", nargs="*", help="files or directories to mount into the container, in the format /outer/path=/inner/path")
+                    help="An existing container to run a shell in, omit "
+                    "CONTAINER to select from available")
+parser.add_argument("--env-file",
+                    help="shell script to set env vars for the container. "
+                    "Normally auto-generated")
+parser.add_argument("--mount", nargs="*",
+                    help="files or directories to mount into the container, "
+                    "in the format /outer/path=/inner/path")
 args = parser.parse_args()
 
 if args.log_task_id:

          
@@ 70,6 134,7 @@ if args.task_id and not args.env_file:
 if not args.env_file and os.path.exists(DEFAULT_ENV_FILE):
     args.env_file = DEFAULT_ENV_FILE
 
+
 def choose(prompt, descriptions):
     if len(descriptions) == 1:
         return 0

          
@@ 82,6 147,7 @@ def choose(prompt, descriptions):
         if idx > 0 and idx <= len(descriptions):
             return idx - 1
 
+
 start_container = False
 if args.container == "infer":
     containers = []

          
@@ 97,7 163,9 @@ if args.container == "infer":
 
 if not args.container and args.image == "infer":
     images = []
-    for line in subprocess.check_output(["docker", "images", "--format", "{{json .}}"], text=True).splitlines():
+    for line in subprocess.check_output([
+            "docker", "images", "--format", "{{json .}}"
+    ], text=True).splitlines():
         images.append(json.loads(line))
     idx = choose(
         "Choose from the following images:",