rowanh

Untitled

Jun 19th, 2019
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.23 KB | None | 0 0
  1. import subprocess
  2. import re
  3.  
  4.  
  5. classes = ['SignupInfo']
  6.  
  7. #
  8. # Get the relevant files and Django app names for the classes we need to augment
  9. #
  10. class_to_file_map = {}
  11. app_to_classes_map = {}
  12. for clazz in classes:
  13. grep_str = subprocess.check_output('grep -r "class ' + clazz + '" **/models.py', shell=True)
  14. matches = re.search('((.*)/models\.py).*', grep_str)
  15.  
  16. app_path = matches.group(2)
  17. django_app = app_path.replace('/', '.')
  18.  
  19. class_to_file_map[clazz] = matches.group(1)
  20.  
  21. if django_app not in app_to_classes_map:
  22. app_to_classes_map[django_app] = []
  23. app_to_classes_map[django_app].append(clazz)
  24.  
  25. #
  26. # Edit the class definitions to no longer have "db_index=False"
  27. #
  28. for clazz, file in class_to_file_map.items():
  29. f = open(file, 'r')
  30.  
  31. # Read the lines, then edit the correct one
  32. lines = f.readlines()
  33. for i in range(len(lines)):
  34. if lines[i].find('class {}'.format(clazz)) != -1:
  35. while True:
  36. i += 1
  37. if lines[i].find('organization =') != -1:
  38. # Funky regex here to capture that db_index may be the first or last arg, which changes
  39. # the position of the comma that we need to delete.
  40. db_index_str = re.search('(db_index=False[,]?[\s]?|[,]?[\s]?db_index=False)', lines[i]).group(1)
  41. lines[i] = lines[i].replace(db_index_str, '')
  42. break
  43. break
  44. f.close()
  45.  
  46. # Write the editted lines back to the file
  47. f = open(file, 'w+')
  48. f.writelines(lines)
  49. f.close()
  50.  
  51. #
  52. # Have Django make the migrations for adding the indexes,
  53. # then have Django spit out the SQL for those migrations,
  54. # then yank the relevant index-creation SQL out of that and augment it to make the index concurrently.
  55. #
  56. app_to_index_creation_sql = {}
  57. django_migration_files_created = []
  58.  
  59. django_migs_output = subprocess.check_output('python manage.py makemigrations', shell=True)
  60. for line in django_migs_output.split('\n'):
  61. mig_number_match = re.search('([0-9]{4})_', line)
  62. if not mig_number_match:
  63. continue
  64. mig_number = mig_number_match.group(1)
  65. mig_app_name = re.search('\s([\S]+)/migrations', line).group(1)
  66.  
  67. django_migration_file_created = re.search('\s([\S]+\.py)', line).group(1)
  68. django_migration_files_created.append(django_migration_file_created)
  69.  
  70. mig_sql = subprocess.check_output('python manage.py sqlmigrate {} {}'.format(mig_app_name, mig_number), shell=True)
  71. index_creation_sql_lines = re.findall('(CREATE INDEX [^;]+;)', mig_sql)
  72.  
  73. for i in range(len(index_creation_sql_lines)):
  74. sql_line = index_creation_sql_lines[i]
  75. sql_line = sql_line.replace('INDEX', 'INDEX CONCURRENTLY')
  76. index_creation_sql_lines[i] = sql_line
  77.  
  78. app_to_index_creation_sql[mig_app_name] = index_creation_sql_lines
  79.  
  80. #
  81. # These migration files are no longer created, we're gonna make new ones from scratch. NUKE TIME
  82. #
  83. for mig_file in django_migration_files_created:
  84. subprocess.check_output('rm {}'.format(mig_file), shell=True)
  85.  
  86. #
  87. # Old migration files: Who are you?
  88. # New migration files: I'm you but better
  89. #
  90. # Time to make new migration files with the SQL for making indexes concurrently
  91. #
  92. for django_app in app_to_classes_map.keys():
  93. makemig_output = subprocess.check_output('python manage.py makemigrations --empty ' + django_app, shell=True)
  94. new_migration_file = re.search('\s([\S]+/migrations.*\.py)', makemig_output).group(1)
  95.  
  96. f = open(new_migration_file, 'r')
  97.  
  98. lines = f.readlines()
  99. for i in range(len(lines)):
  100. line = lines[i]
  101. if line.startswith('class'):
  102. break
  103.  
  104. lines.insert(i, '\n')
  105. for j, sql_line in enumerate(app_to_index_creation_sql[django_app]):
  106. lines.insert(i, 'INDEX_CREATION_SQL_{} = \'{}\'\n'.format(j, sql_line))
  107. lines.insert(i, 'from django.conf import settings\n')
  108.  
  109. lines.append(' if not settings.INITIAL_DATABASE_SETUP:\n')
  110. for j, __ in enumerate(app_to_index_creation_sql[django_app]):
  111. lines.append(' operations.append(migrations.RunSQL(INDEX_CREATION_SQL_{}), migrations.RunSQL.noop)\n'.format(j))
  112. lines.append(' atomic = False')
  113.  
  114. f.close()
  115.  
  116. f = open(new_migration_file, 'w+')
  117. f.writelines(lines)
  118. f.close()
  119.  
  120. #
  121. # Take a quick trip back in time to erase Django's memory of ever having db_index=False for the associated classes
  122. #
  123. for django_app, classes in app_to_classes_map.items():
  124. for clazz in classes:
  125.  
  126. # We'll do this in a try/catch, since there's a chance that there have been
  127. # no AddField/AlterField operations on Organization for this class
  128. try:
  129. grep_output = subprocess.check_output('grep -i "\(addfield\|alterfield\|createmodel\)" {}/migrations/* -A 10 | grep -i organization -B 10 | grep -i {}'
  130. .format(django_app.replace('.', '/'),
  131. clazz),
  132. shell=True)
  133. except:
  134. continue
  135.  
  136. files_to_alter = []
  137. for line in grep_output.split('\n'):
  138. if line:
  139. files_to_alter.append(re.search('([\S]+\.py)', line).group(1))
  140.  
  141. for file in files_to_alter:
  142. f = open(file, 'r')
  143.  
  144. lines = f.readlines()
  145.  
  146. upcoming_edit_line = False
  147. for i in range(len(lines)):
  148. line = lines[i]
  149. found_index = max(line.find(clazz.lower()), line.find(clazz))
  150. if found_index != -1 and line[found_index - 1] == "'":
  151. upcoming_edit_line = True
  152.  
  153. if upcoming_edit_line and line.find('db_index') != -1:
  154. # Same funky regex here as before to catch the fact that the comma we need
  155. # to delete may be before or after the arg but NOT BOTH
  156. db_index_str = re.search('(db_index=False[,]?[\s]?|[,]?[\s]?db_index=False)', line).group(1)
  157. lines[i] = line.replace(db_index_str, '')
  158. upcoming_edit_line = False
  159.  
  160. f.close()
  161.  
  162. f = open(file, 'w+')
  163. f.writelines(lines)
  164. f.close()
Add Comment
Please, Sign In to add comment