|  | # Licensed to the Apache Software Foundation (ASF) under one | 
|  | # or more contributor license agreements.  See the NOTICE file | 
|  | # distributed with this work for additional information | 
|  | # regarding copyright ownership.  The ASF licenses this file | 
|  | # to you under the Apache License, Version 2.0 (the | 
|  | # "License"); you may not use this file except in compliance | 
|  | # with the License.  You may obtain a copy of the License at | 
|  | # | 
|  | #     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  | """ | 
|  | A script to use nodetool to generate documentation for nodetool | 
|  | """ | 
|  | from __future__ import print_function | 
|  |  | 
|  | import os | 
|  | import re | 
|  | import sys | 
|  | import subprocess | 
|  | from subprocess import PIPE | 
|  | from subprocess import Popen | 
|  | from itertools import islice | 
|  | from threading import Thread | 
|  |  | 
|  | batch_size = 3 | 
|  |  | 
|  | if(os.environ.get("SKIP_NODETOOL") == "1"): | 
|  | sys.exit(0) | 
|  |  | 
|  |  | 
|  | nodetool = "../bin/nodetool" | 
|  | outdir = "modules/cassandra/pages/managing/tools/nodetool" | 
|  | examplesdir = "modules/cassandra/examples/TEXT/NODETOOL" | 
|  | helpfilename = outdir + "/nodetool.txt" | 
|  | command_re = re.compile("(    )([_a-z]+)") | 
|  | commandADOCContent = "= {0}\n\n== Usage\n[source,plaintext]\n----\ninclude::cassandra:example$TEXT/NODETOOL/{0}.txt[]\n----\n" | 
|  |  | 
|  | # https://docs.python.org/3/library/itertools.html#itertools-recipes | 
|  | def batched(iterable, n): | 
|  | "Batch data into tuples of length n. The last batch may be shorter." | 
|  | # batched('ABCDEFG', 3) --> ABC DEF G | 
|  | if n < 1: | 
|  | raise ValueError('n must be at least one') | 
|  | it = iter(iterable) | 
|  | batch = tuple(islice(it, n)) | 
|  | while (batch): | 
|  | yield batch | 
|  | batch = tuple(islice(it, n)) | 
|  |  | 
|  | # create the documentation directory | 
|  | if not os.path.exists(outdir): | 
|  | os.makedirs(outdir) | 
|  |  | 
|  | # create the base help file to use for discovering the commands | 
|  | def create_help_file(): | 
|  | with open(helpfilename, "w+") as output_file: | 
|  | try: | 
|  | proc = subprocess.Popen([nodetool, "help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
|  | out, err = proc.communicate() | 
|  | if proc.returncode != 0: | 
|  | print( | 
|  | 'ERROR: Nodetool failed to run, you likely need to build ' | 
|  | 'cassandra using ant jar from the top level directory' | 
|  | ) | 
|  | raise subprocess.CalledProcessError(proc.returncode, proc.args, output=out, stderr=err) | 
|  |  | 
|  | # Wrap the initial "usage: ..." block | 
|  | usage_block = re.search(r'usage:.*?\n\n', out.decode('utf-8'), re.DOTALL | re.MULTILINE) | 
|  | if usage_block: | 
|  | output_file.write("[source,console]\n----\n") | 
|  | output_file.write(usage_block.group(0)) | 
|  | output_file.write("----\n") | 
|  | out = out.decode('utf-8').replace(usage_block.group(0), '') | 
|  | else: | 
|  | raise ValueError("No usage block matched in nodetool help output") | 
|  | output_file.write(out) | 
|  | except subprocess.CalledProcessError as cpe: | 
|  | raise cpe | 
|  |  | 
|  | # for a given command, create the help file and an ADOC file to contain it | 
|  | def create_adoc(command): | 
|  | if command: | 
|  | cmdName = command.group(0).strip() | 
|  | cmdFilename = examplesdir + "/" + cmdName + ".txt" | 
|  | adocFilename = outdir + "/" + cmdName + ".adoc" | 
|  | with open(cmdFilename, "wb+") as cmdFile: | 
|  | proc = Popen([nodetool, "help", cmdName], stdin=PIPE, stdout=PIPE) | 
|  | (out, err) = proc.communicate() | 
|  | cmdFile.write(out) | 
|  | with open(adocFilename, "w+") as adocFile: | 
|  | adocFile.write(commandADOCContent.format(cmdName,cmdName,cmdName)) | 
|  |  | 
|  | # create base file | 
|  | create_help_file() | 
|  |  | 
|  | # create the main usage page | 
|  | with open(outdir + "/nodetool.adoc", "w+") as output: | 
|  | with open(helpfilename, "r+") as helpfile: | 
|  | output.write("= Nodetool\n\n== Usage\n\n") | 
|  | for commandLine in helpfile: | 
|  | command = command_re.sub(r'\nxref:cassandra:managing/tools/nodetool/\2.adoc[\2] - ',commandLine) | 
|  | output.write(command) | 
|  |  | 
|  | # create the command usage pages | 
|  | with open(helpfilename, "r+") as helpfile: | 
|  | for clis in batched(helpfile, batch_size): | 
|  | threads = [] | 
|  | for commandLine in clis: | 
|  | command = command_re.match(commandLine) | 
|  | t = Thread(target=create_adoc, args=[command]) | 
|  | threads.append(t) | 
|  | t.start() | 
|  | for t in threads: | 
|  | t.join() |