2016-04-05 00:27:37 +02:00
|
|
|
|
2017-11-16 00:43:27 +01:00
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
from django.conf import settings
|
2016-04-05 00:27:37 +02:00
|
|
|
from django.core.management import call_command
|
2016-11-03 10:22:19 +01:00
|
|
|
from django.core.management.base import BaseCommand, CommandParser
|
2016-04-05 00:27:37 +02:00
|
|
|
|
|
|
|
from zerver.lib.export import do_import_realm
|
2017-11-16 00:43:27 +01:00
|
|
|
from zerver.models import Client, DefaultStream, Huddle, \
|
|
|
|
Message, Realm, RealmDomain, RealmFilter, Recipient, \
|
|
|
|
Stream, Subscription, UserMessage, UserProfile
|
2016-04-05 00:27:37 +02:00
|
|
|
|
2017-05-07 17:15:24 +02:00
|
|
|
Model = Any # TODO: make this mypy type more specific
|
2016-09-12 00:49:00 +02:00
|
|
|
|
2016-04-05 00:27:37 +02:00
|
|
|
class Command(BaseCommand):
|
|
|
|
help = """Import Zulip database dump files into a fresh Zulip instance.
|
|
|
|
|
|
|
|
This command should be used only on a newly created, empty Zulip instance to
|
2017-10-06 17:45:22 +02:00
|
|
|
import a database dump from one or more JSON files."""
|
2016-04-05 00:27:37 +02:00
|
|
|
|
2017-10-26 11:35:57 +02:00
|
|
|
def add_arguments(self, parser: CommandParser) -> None:
|
2016-11-03 10:22:19 +01:00
|
|
|
parser.add_argument('--destroy-rebuild-database',
|
|
|
|
dest='destroy_rebuild_database',
|
|
|
|
default=False,
|
|
|
|
action="store_true",
|
|
|
|
help='Destroys and rebuilds the databases prior to import.')
|
|
|
|
|
|
|
|
parser.add_argument('--import-into-nonempty',
|
|
|
|
dest='import_into_nonempty',
|
|
|
|
default=False,
|
|
|
|
action="store_true",
|
|
|
|
help='Import into an existing nonempty database.')
|
2017-10-06 17:45:22 +02:00
|
|
|
|
|
|
|
parser.add_argument('export_files', nargs='+',
|
|
|
|
metavar='<export file>',
|
|
|
|
help="list of JSON exports to import")
|
2017-10-06 17:41:01 +02:00
|
|
|
parser.formatter_class = argparse.RawTextHelpFormatter
|
2016-04-05 00:27:37 +02:00
|
|
|
|
2017-10-26 11:35:57 +02:00
|
|
|
def new_instance_check(self, model: Model) -> None:
|
2016-04-05 00:27:37 +02:00
|
|
|
count = model.objects.count()
|
|
|
|
if count:
|
2016-12-03 18:07:49 +01:00
|
|
|
print("Zulip instance is not empty, found %d rows in %s table. "
|
2016-12-11 14:30:45 +01:00
|
|
|
% (count, model._meta.db_table))
|
2017-11-09 11:45:56 +01:00
|
|
|
print("You may use --destroy-rebuild-database to destroy and "
|
|
|
|
"rebuild the database prior to import.")
|
2016-04-05 00:27:37 +02:00
|
|
|
exit(1)
|
|
|
|
|
2017-10-26 11:35:57 +02:00
|
|
|
def do_destroy_and_rebuild_database(self, db_name: str) -> None:
|
2016-04-05 00:27:37 +02:00
|
|
|
call_command('flush', verbosity=0, interactive=False)
|
|
|
|
subprocess.check_call([os.path.join(settings.DEPLOY_ROOT, "scripts/setup/flush-memcached")])
|
|
|
|
|
2017-10-26 11:35:57 +02:00
|
|
|
def handle(self, *args: Any, **options: Any) -> None:
|
2016-04-05 00:27:37 +02:00
|
|
|
models_to_import = [Realm, Stream, UserProfile, Recipient, Subscription,
|
2017-03-31 16:20:07 +02:00
|
|
|
Client, Message, UserMessage, Huddle, DefaultStream, RealmDomain,
|
2016-12-11 14:30:45 +01:00
|
|
|
RealmFilter]
|
2016-04-05 00:27:37 +02:00
|
|
|
|
|
|
|
if options["destroy_rebuild_database"]:
|
|
|
|
print("Rebuilding the database!")
|
|
|
|
db_name = settings.DATABASES['default']['NAME']
|
|
|
|
self.do_destroy_and_rebuild_database(db_name)
|
|
|
|
elif not options["import_into_nonempty"]:
|
|
|
|
for model in models_to_import:
|
|
|
|
self.new_instance_check(model)
|
|
|
|
|
2017-10-06 17:45:22 +02:00
|
|
|
for path in options['export_files']:
|
2016-04-05 00:27:37 +02:00
|
|
|
if not os.path.exists(path):
|
|
|
|
print("Directory not found: '%s'" % (path,))
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
print("Processing dump: %s ..." % (path,))
|
|
|
|
do_import_realm(path)
|