Skip to content

Commit 90aa506

Browse files
committed
Introduce djangonaut migration mode.
1 parent 61a1ace commit 90aa506

File tree

2 files changed

+160
-3
lines changed

2 files changed

+160
-3
lines changed

djangonaut.el

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,12 +912,14 @@ user input. HIST is a variable to store history of choices."
912912
(defun djangonaut-find-migration ()
913913
"Open definition of the Django migration."
914914
(interactive)
915-
(djangonaut-find-file-and-line #'find-file "Migration: " (djangonaut-get-migrations) 'djangonaut-migrations-history))
915+
(djangonaut-find-file-and-line #'find-file "Migration: " (djangonaut-get-migrations) 'djangonaut-migrations-history)
916+
(djangonaut-migration-mode +1))
916917

917918
(defun djangonaut-find-migration-other-window ()
918919
"Open definition of the Django migration in the other window."
919920
(interactive)
920-
(djangonaut-find-file-and-line #'find-file-other-window "Migration: " (djangonaut-get-migrations) 'djangonaut-migrations-history))
921+
(djangonaut-find-file-and-line #'find-file-other-window "Migration: " (djangonaut-get-migrations) 'djangonaut-migrations-history)
922+
(djangonaut-migration-mode +1))
921923

922924
(defun djangonaut-find-sql-function ()
923925
"Open definition of the Django sql function."
@@ -1181,6 +1183,156 @@ user input. HIST is a variable to store history of choices."
11811183
(djangonaut-mode 1)))))))
11821184
:require 'djangonaut)
11831185

1186+
(defvar djangonaut-get-previous-migration-code "
1187+
from inspect import getsourcefile, findsource
1188+
1189+
from django.db.migrations.loader import MigrationLoader
1190+
1191+
loader = MigrationLoader(connection=None, load=False)
1192+
loader.load_disk()
1193+
1194+
for (label, module_name), migration in sorted(loader.disk_migrations.items()):
1195+
Migration = migration.__class__
1196+
migration_file = getsourcefile(Migration)
1197+
if migration_file == sys.argv[-1]:
1198+
dependencies = [loader.disk_migrations[i] for i in Migration.dependencies]
1199+
files = {getsourcefile(dep.__class__): dep.__class__ for dep in dependencies}
1200+
longest = max(files, key=lambda x: len(os.path.commonprefix([migration_file, x])))
1201+
dependency = files[longest]
1202+
result[getsourcefile(dependency)] = findsource(dependency)[1]
1203+
break
1204+
1205+
" "Python source code to get previous migration file.")
1206+
1207+
(defvar djangonaut-get-next-migration-code "
1208+
from inspect import getsourcefile, findsource
1209+
1210+
from django.db.migrations.loader import MigrationLoader
1211+
1212+
loader = MigrationLoader(connection=None, load=False)
1213+
loader.load_disk()
1214+
1215+
for (label, module_name), migration in sorted(loader.disk_migrations.items()):
1216+
Migration = migration.__class__
1217+
migration_file = getsourcefile(Migration)
1218+
if migration_file == sys.argv[-1]:
1219+
have_dependency = [other for other in loader.disk_migrations.values() if (label, module_name) in other.dependencies]
1220+
files = {getsourcefile(other.__class__): other.__class__ for other in have_dependency}
1221+
longest = max(files, key=lambda x: len(os.path.commonprefix([migration_file, x])))
1222+
parent = files[longest]
1223+
result[getsourcefile(parent)] = findsource(parent)[1]
1224+
break
1225+
1226+
" "Python source code to get next migration file.")
1227+
1228+
(defvar djangonaut-rerun-migration-code "
1229+
from __future__ import print_function
1230+
1231+
from django.apps import apps
1232+
from django.conf import settings
1233+
apps.populate(settings.INSTALLED_APPS)
1234+
1235+
import sys
1236+
from inspect import getsourcefile
1237+
1238+
from django.core.management import call_command
1239+
from django.db.migrations.loader import MigrationLoader
1240+
1241+
loader = MigrationLoader(connection=None, load=False)
1242+
loader.load_disk()
1243+
1244+
for (label, module_name), migration in sorted(loader.disk_migrations.items()):
1245+
Migration = migration.__class__
1246+
if getsourcefile(Migration) == sys.argv[-1]:
1247+
for app_name, migration_name in Migration.dependencies:
1248+
call_command('migrate', app_name, migration_name)
1249+
break
1250+
1251+
call_command('migrate')
1252+
1253+
" "Python source code to rerun migration file.")
1254+
1255+
(defun djangonaut-get-previous-migration (filename)
1256+
"Execute and parse python code to get previous migration FILENAME."
1257+
(djangonaut-read (djangonaut-call djangonaut-get-previous-migration-code filename)))
1258+
1259+
(defun djangonaut-get-next-migration (filename)
1260+
"Execute and parse python code to get next migration FILENAME."
1261+
(djangonaut-read (djangonaut-call djangonaut-get-next-migration-code filename)))
1262+
1263+
(defun djangonaut-find-previous-migration (filename)
1264+
""
1265+
(interactive (list (buffer-file-name)))
1266+
(let ((migration (djangonaut-get-previous-migration
1267+
(pythonic-python-readable-file-name filename))))
1268+
(when migration
1269+
;; FIXME: Copy-pasted from `djangonaut-find-file-and-line'.
1270+
(let* ((value (caar migration))
1271+
(lineno (cadr migration)))
1272+
(apply #'find-file (pythonic-emacs-readable-file-name value) nil)
1273+
(goto-char (point-min))
1274+
(forward-line lineno)
1275+
(run-hooks 'djangonaut-navigate-line-hook)
1276+
(djangonaut-migration-mode +1)))))
1277+
1278+
(defun djangonaut-find-next-migration (filename)
1279+
""
1280+
(interactive (list (buffer-file-name)))
1281+
(let ((migration (djangonaut-get-next-migration
1282+
(pythonic-python-readable-file-name filename))))
1283+
(when migration
1284+
;; FIXME: Copy-pasted from `djangonaut-find-file-and-line'.
1285+
(let* ((value (caar migration))
1286+
(lineno (cadr migration)))
1287+
(apply #'find-file (pythonic-emacs-readable-file-name value) nil)
1288+
(goto-char (point-min))
1289+
(forward-line lineno)
1290+
(run-hooks 'djangonaut-navigate-line-hook)
1291+
(djangonaut-migration-mode +1)))))
1292+
1293+
(defun djangonaut-rerun-current-migration (filename)
1294+
"Reapply migration from the FILENAME."
1295+
(interactive (list (buffer-file-name)))
1296+
;; FIXME: Copy-pasted from run command.
1297+
(let* ((buffer (get-buffer-create "*Django*"))
1298+
(process (get-buffer-process buffer)))
1299+
(when (and process (process-live-p process))
1300+
(setq buffer (generate-new-buffer "*Django*")))
1301+
(with-current-buffer buffer
1302+
(hack-dir-local-variables-non-file-buffer)
1303+
(pythonic-start-process :process "djangonaut"
1304+
:buffer buffer
1305+
:args (list "-c" djangonaut-rerun-migration-code (pythonic-python-readable-file-name filename))
1306+
:cwd (pythonic-emacs-readable-file-name (djangonaut-get-project-root))
1307+
:filter (lambda (process string)
1308+
(comint-output-filter process (ansi-color-apply string))))
1309+
(let ((inhibit-read-only t))
1310+
(erase-buffer))
1311+
(comint-mode)
1312+
(setq-local comint-prompt-read-only t)
1313+
(pop-to-buffer buffer))))
1314+
1315+
(defvar djangonaut-migration-command-map
1316+
(let ((map (make-sparse-keymap)))
1317+
(define-key map (kbd "<") 'djangonaut-find-previous-migration)
1318+
(define-key map (kbd ">") 'djangonaut-find-next-migration)
1319+
(define-key map (kbd "@") 'djangonaut-rerun-current-migration)
1320+
map))
1321+
1322+
(defvar djangonaut-migration-mode-map
1323+
(let ((map (make-sparse-keymap)))
1324+
(define-key map djangonaut-keymap-prefix djangonaut-migration-command-map)
1325+
map))
1326+
1327+
(defvar djangonaut-migration-mode-lighter "")
1328+
1329+
(define-minor-mode djangonaut-migration-mode
1330+
"Minor mode to interact with Django migration modules.
1331+
1332+
\\{djangonaut-migration-mode-map}"
1333+
:lighter djangonaut-migration-mode-lighter
1334+
:keymap djangonaut-migration-mode-map)
1335+
11841336
(provide 'djangonaut)
11851337

11861338
;;; djangonaut.el ends here

test/djangonaut-test.el

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@
3030
(djangonaut-get-template-tags)
3131
(djangonaut-get-template-filters)
3232
(djangonaut-get-static-files)
33-
(djangonaut-get-settings-path)))
33+
(djangonaut-get-settings-path)
34+
;; FIXME: Test
35+
;; `djangonaut-get-previous-migration-code',
36+
;; `djangonaut-get-next-migration-code' and
37+
;; `djangonaut-rerun-migration-code'.
38+
))
3439
(let* ((name (format "test-%s" (car args)))
3540
(symbol (intern name)))
3641
(eval

0 commit comments

Comments
 (0)