Advertisement
Guest User

Futureize script

a guest
Jul 5th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.48 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. """Usage:
  4.  
  5. * ./update.py folder  -> preview which files in folder need changes
  6. * ./update.py folder file.py target  -> update file
  7. * ./update.py folder file.py --preview  -> preview changes to that file
  8. * ./update.py folder file.py target --test  -> update file with tests folder as root
  9. * ./update.py folder file.py --test --preview  -> update file with tests folder as root
  10. """
  11.  
  12. import subprocess
  13. import itertools
  14. import argparse
  15.  
  16. from typing import List
  17.  
  18.  
  19. SRC_ROOT = 'src/python/pants'
  20. TEST_ROOT = 'tests/python/pants_test'
  21.  
  22.  
  23. def main() -> None:
  24.   parser = create_parser()
  25.   args = parser.parse_args()
  26.   base_root = TEST_ROOT if args.test else SRC_ROOT
  27.   target_root = f'{base_root}/{args.folder}'
  28.   if not args.file_target:
  29.     check_what_needs_changes(f'{target_root}/*.py')
  30.     return
  31.   file_path = f'{target_root}/{args.file_target}'
  32.   pants_target_path = f'{target_root}:{args.pants_target}'
  33.   # execute
  34.   if args.preview:
  35.     preview_changes(file_path)
  36.     return
  37.   call_futurize(file_path)
  38.   if not file_changed(file_path):
  39.     return
  40.   move_imports_below_future(file_path)
  41.   update_build_dependencies(target_root, args.pants_target)
  42.   call_pants_fmt(pants_target_path)
  43.   call_pants_test(pants_target_path)
  44.  
  45.  
  46. def create_parser() -> argparse.ArgumentParser:
  47.   parser = argparse.ArgumentParser()
  48.   parser.add_argument('folder')
  49.   parser.add_argument('file_target', nargs='?', default=None)
  50.   parser.add_argument('pants_target', nargs='?', default=None)
  51.   parser.add_argument('-t', '--test', action='store_true')
  52.   parser.add_argument('-p', '--preview', action='store_true')
  53.   return parser
  54.  
  55.  
  56. def check_what_needs_changes(folder: str) -> None:
  57.   subprocess.run(
  58.     f'build-support/pants_dev_deps.venv/bin/futurize --stage2 --no-diffs {folder}',
  59.     shell=True
  60.   )
  61.  
  62.  
  63. def call_futurize(path: str) -> None:
  64.   subprocess.run([
  65.     'build-support/pants_dev_deps.venv/bin/futurize',
  66.     '--write',
  67.     '--nobackup',
  68.     '--stage2',
  69.     path
  70.   ])
  71.  
  72.  
  73. def preview_changes(path: str) -> None:
  74.   subprocess.run([
  75.     'build-support/pants_dev_deps.venv/bin/futurize',
  76.     '--stage2',
  77.     path
  78.   ])
  79.  
  80.  
  81. def file_changed(path: str) -> bool:
  82.   git_changes = subprocess.run(['git', 'ls-files', '-m'],
  83.                                stdout=subprocess.PIPE,
  84.                                encoding='utf-8').stdout.strip()
  85.   return path in git_changes
  86.  
  87.  
  88. def move_imports_below_future(path: str) -> None:
  89.  
  90.     def read_lines_before_future_import(path: str) -> List[str]:
  91.       with open(path, 'r') as f:
  92.         return list(itertools.takewhile(lambda line: 'from __future__ import' not in line, f))
  93.  
  94.     # find line numbers
  95.     header_lines = read_lines_before_future_import(path)
  96.     new_imports_above_future = [i for i, line in enumerate(header_lines)
  97.                                 if '#' not in line and line != '\n']
  98.     future_import_first_line = len(header_lines)
  99.     future_import_last_line = len(header_lines) + 1
  100.  
  101.     # skip if not needed
  102.     if not new_imports_above_future:
  103.       return
  104.  
  105.     # get lines
  106.     with open(path, 'r') as f:
  107.       lines = list(f.readlines())
  108.  
  109.     # overwrite
  110.     with open(path, 'w') as f:
  111.       for index in new_imports_above_future:
  112.         lines.insert(future_import_last_line + 1, lines[index])
  113.       pop_index = future_import_first_line - 1
  114.       for _ in new_imports_above_future:
  115.         lines.pop(pop_index)
  116.         pop_index -= 1
  117.       f.writelines(lines)
  118.  
  119.  
  120. def call_pants_fmt(pants_target_path: str) -> None:
  121.   subprocess.run([
  122.     './pants',
  123.     'fmt',
  124.     pants_target_path
  125.   ])
  126.  
  127.  
  128. def call_pants_test(pants_test_target_path: str) -> None:
  129.   subprocess.run([
  130.     './pants',
  131.     'test',
  132.     pants_test_target_path
  133.   ])
  134.  
  135.  
  136. def update_build_dependencies(folder: str, pants_target: str) -> None:
  137.   build_file = f'{folder}/BUILD'
  138.   with open(build_file, 'r') as f:
  139.     lines = list(f.readlines())
  140.   target_index = lines.index(f"  name = '{pants_target}',\n")
  141.   for i, line in enumerate(lines[target_index:]):
  142.     if 'dependencies = [' in line:
  143.       lines.insert(target_index + i + 1, "    '3rdparty/python:future',\n")
  144.       break
  145.     if line == '\n':  # dependencies section doesn't exist for target
  146.       lines.insert(target_index + 2, '  dependencies = [\n')
  147.       lines.insert(target_index + 3, "    '3rdparty/python:future',\n")
  148.       lines.insert(target_index + 4, '  ]\n')
  149.   with open(build_file, 'w') as f:
  150.     f.writelines(lines)
  151.  
  152.  
  153. if __name__ == '__main__':
  154.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement