| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2021 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| #### CATEGORY=Documentation |
| ### Helper tool to batch move docs from one location to another |
| |
| ## Usage: fx move-docs [--dry-run] INPUT_FILE |
| ## cat INPUT_FILE | fx move-docs [--dry-run] |
| ## echo "docs/orig/file.md doc/new_location/_toc.yaml" | fx move-docs [--dry-run] |
| ## |
| ## INPUT_FILE is a file with two columns, where the first column |
| ## is the original location of the doc to be moved, and the second |
| ## line is the destination _toc.yaml file. |
| ## |
| ## This tool will locate the original and destination _toc.yaml files, |
| ## update them and update any reference to the original file. |
| ## |
| ## It will also create a proper entry in the _redirects.yaml file. |
| ## |
| import argparse |
| import os |
| import sys |
| import shutil |
| import re |
| import fnmatch |
| import pathlib |
| |
| TOC_H="""# Copyright 2021 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Please, read https://fuchsia.dev/fuchsia-src/contribute/docs/documentation-navigation-toc |
| # before making changes to this file, and add a member of the fuchsia.dev |
| # team as reviewer. |
| toc: """ |
| |
| def process_file(orig, dest_yaml): |
| print("***** Processing %s:" % orig) |
| |
| orig_yaml=os.path.join(os.path.dirname(orig), "_toc.yaml") |
| dest=os.path.join(os.path.dirname(dest_yaml), os.path.basename(orig)) |
| |
| if not os.path.basename(dest_yaml) == '_toc.yaml': |
| print("Destination TOC has to be named _toc.yaml: %s" % dest_yaml) |
| return False |
| if not os.path.exists(orig): |
| print("Original file does not exist: %s" % orig) |
| return False |
| if not os.path.exists(orig_yaml): |
| print("_toc.yaml for the original file does not exist: %s" % orig_yaml) |
| return False |
| if os.path.exists(dest): |
| print("Destination file exists: %s" % dest) |
| return False |
| if not os.path.exists(dest_yaml): |
| if dry_run: |
| print("...dryrun... Creating destination _toc.yaml: %s" % dest_yaml) |
| else: |
| pathlib.Path(os.path.dirname(dest_yaml)).mkdir(parents=True, exist_ok=True) |
| with open(dest_yaml, "w") as f: |
| f.write(TOC_H) |
| |
| # We can't use yaml library because it throws away comments and styles. Since |
| # we just want to do basic manipulation on relatively well-behaved yaml |
| # files, we will hack it. |
| with open(orig_yaml) as f: |
| orig_lines = f.readlines() |
| |
| new_lines = [] |
| entry=[] |
| target_entry=None |
| started_toc=False |
| is_target=False |
| for line in orig_lines: |
| if not started_toc: |
| new_lines.append(line) |
| if re.search(r'^\s*toc:\s*$', line): |
| started_toc=True |
| continue |
| if re.search(r'^\s*- ', line): |
| if len(entry): |
| if is_target: |
| target_entry = entry |
| else: |
| new_lines.extend(entry) |
| entry = [] |
| is_target = False |
| elif re.search(r'\s*[\s-]\s*path:\s*"?' + re.escape("/" + orig), line): |
| is_target = True |
| entry.append(line) |
| |
| if len(entry): |
| if is_target: |
| target_entry = entry |
| else: |
| new_lines.extend(entry) |
| |
| if not target_entry: |
| print("ERROR: could not find the original TOC entry in %s" % orig_yaml) |
| return False |
| |
| if dry_run: |
| print("...dryrun... Removing entry from %s:" % orig_yaml) |
| print(''.join(target_entry)) |
| else: |
| with open(orig_yaml, 'w') as f: |
| print(''.join(new_lines), file=f) |
| |
| # Add the entry to the destination _toc.yaml file |
| new_target_entry = [re.sub(re.escape(orig), dest, line) for line in target_entry] |
| if dry_run: |
| print("...dryrun... Adding entry to the end of %s:" % dest_yaml) |
| print(''.join(new_target_entry)) |
| else: |
| with open(dest_yaml, 'a') as f: |
| print('\n', file=f) |
| print(''.join(new_target_entry), file=f) |
| |
| # Move the original file to the destination |
| if dry_run: |
| print("...dryrun... Moving file %s to %s" % (orig, dest)) |
| else: |
| shutil.move(orig, dest) |
| |
| # Replace usage of the original file in all *.md docs |
| docs_dir=os.path.join(os.environ['FUCHSIA_DIR'], 'docs') |
| find_replace(docs_dir, orig, dest, '*.md') |
| |
| # Add an entry to _redirects.yaml |
| redirect=['- from: /%s' % orig, ' to: /%s' % dest] |
| redirect_file=os.path.join(docs_dir, '_redirects.yaml') |
| if dry_run: |
| print('...dryrun... Adding entry to docs/_redirects.yaml:') |
| print('\n'.join(redirect)) |
| print('\n') |
| else: |
| with open(redirect_file, 'a' if os.path.exists(redirect_file) else 'w') as f: |
| print('\n', file=f) |
| print('\n'.join(redirect), file=f) |
| |
| return True |
| |
| def find_replace(directory, find, replace, filePattern): |
| for path, dirs, files in os.walk(os.path.abspath(directory)): |
| for filename in fnmatch.filter(files, filePattern): |
| filepath = os.path.join(path, filename) |
| with open(filepath) as f: |
| s = f.read() |
| new_s = s.replace(find, replace) |
| if s != new_s: |
| if dry_run: |
| print("### Changing references in %s" % |
| os.path.relpath(filepath, directory)) |
| else: |
| with open(filepath, "w") as f: |
| f.write(new_s) |
| |
| def is_file_toc(filename, toc): |
| if filename[0] != '/': |
| filename='/' + filename |
| return toc['path'] == filename |
| |
| def main(): |
| parser = argparse.ArgumentParser( |
| description=u"Move docs in batch") |
| |
| parser.add_argument( |
| "input_file", |
| nargs=u"?", |
| default=u"", |
| help="Filename with one entry per line, each entry being space-separated strings for the original file and the destination _toc.yaml") |
| |
| parser.add_argument( |
| "--dry-run", |
| action="store_const", |
| default=False, |
| const=True, |
| help="Does not modify any file", |
| ) |
| |
| args = parser.parse_args() |
| |
| global dry_run |
| dry_run = args.dry_run |
| |
| if args.input_file: |
| input_file = open(args.input_file) |
| else: |
| input_file = sys.stdin |
| |
| |
| for line in input_file.readlines(): |
| orig, dest_yaml = line.split() |
| orig = orig[1:] if orig.startswith('/docs') else orig |
| dest_yaml = dest_yaml[1:] if dest_yaml.startswith('/docs') else dest_yaml |
| process_file(orig, dest_yaml) |
| |
| if input_file is not sys.stdin: |
| input_file.close() |
| |
| sys.exit(0) |
| |
| |
| if __name__ == u"__main__": |
| sys.exit(main()) |