123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- import filecmp
- import json
- import os
- import shutil
- import sys
- from django.utils.crypto import get_random_string
- from django.core.management import execute_from_command_line as django_command_line
- import iepy
- from iepy import defaults
- from iepy.utils import DIRS, unzip_from_url
- THIS_FOLDER = os.path.dirname(os.path.abspath(__file__))
- class InstanceManager:
- # class instead of a fuction just for allowing better code organization
- files_to_copy = [
- "csv_to_iepy.py",
- "preprocess.py",
- "iepy_runner.py",
- "iepy_rules_runner.py",
- "rules_verifier.py",
- "manage.py",
- "gazettes_loader.py",
- ]
- steps = [
- 'create_folders',
- 'create_init_file',
- 'copy_bin',
- 'create_rules_file',
- 'create_extractor_config_file',
- # Put this following step at the end of all the steps that doesnt need settings
- 'configure_settings_file',
- 'migrate_db',
- 'create_db_user',
- 'greetings',
- ]
- def __init__(self, folder_path, lang='en'):
- self.folder_path = folder_path
- self.abs_folder_path = os.path.abspath(self.folder_path)
- self.creating = True
- self.lang = lang
- def _run_steps(self):
- for step_name in self.steps:
- step = getattr(self, step_name)
- step()
- def create(self):
- if os.path.exists(self.folder_path):
- print("Error: folder already exists")
- sys.exit(1)
- self._run_steps()
- def upgrade(self):
- if not os.path.exists(self.folder_path):
- print("Error: instance folder does not exist")
- sys.exit(1)
- try:
- actual_path = iepy.setup(self.folder_path, _safe_mode=True)
- except ValueError as err:
- print(err)
- sys.exit(1)
- finally:
- self.folder_path = actual_path
- self.abs_folder_path = os.path.abspath(self.folder_path)
- from django.conf import settings
- self.old_version = settings.IEPY_VERSION
- if settings.IEPY_VERSION == iepy.__version__:
- print("Iepy instance '{}' is already up to date.".format(self.folder_path))
- return
- print("Upgrading iepy instance '{}' from {} to {}".format(
- self.folder_path, self.old_version, iepy.__version__))
- self.creating = False
- self.old_version_path = self.download_old_iepy_version()
- self._run_steps()
- def download_old_iepy_version(self):
- oldv = self.old_version
- url = "https://pypi.python.org/packages/source/i/iepy/iepy-{}.tar.gz".format(oldv)
- old_versions_path = os.path.join(DIRS.user_data_dir, 'old_versions')
- os.makedirs(old_versions_path, exist_ok=True)
- asked_tag_path = os.path.join(old_versions_path, 'iepy-{}'.format(oldv))
- if not os.path.exists(asked_tag_path):
- print ('Downloading old iepy version {} for allowing patches'.format(oldv))
- unzip_from_url(url, old_versions_path)
- print('Done')
- return asked_tag_path
- def create_folders(self):
- self.bin_folder = os.path.join(self.folder_path, "bin")
- os.makedirs(self.bin_folder, exist_ok=not self.creating)
- def create_init_file(self):
- rules_filepath = os.path.join(self.folder_path, "__init__.py")
- with open(rules_filepath, "w") as filehandler:
- filehandler.write("from . import rules")
- def copy_bin(self):
- # Create folders
- for filename in self.files_to_copy:
- destination = os.path.join(self.bin_folder, filename)
- self._copy_file(filename, destination)
- def create_rules_file(self):
- rules_filepath = os.path.join(self.folder_path, "rules.py")
- if self.creating:
- with open(rules_filepath, "w") as filehandler:
- filehandler.write("# Write here your rules\n")
- filehandler.write("# RELATION = 'your relation here'\n")
- def create_extractor_config_file(self):
- # Create extractor config
- config_filepath = os.path.join(self.folder_path, "extractor_config.json")
- def do_it():
- with open(config_filepath, "w") as filehandler:
- json.dump(defaults.extractor_config, filehandler, indent=4)
- if self.creating:
- do_it()
- else:
- if json.load(open(config_filepath)) != defaults.extractor_config:
- msg = 'Should we override your extraction config settings?'
- msg += ' (existing version will be backed up first)'
- if self.prompt(msg):
- self.preserve_old_file_version_as_copy(config_filepath)
- do_it()
- print ('Extraction configs upgraded.')
- else:
- print ('Extraction configs left untouched.')
- def _copy_file(self, filename, destination):
- filepath = os.path.join(THIS_FOLDER, filename)
- def do_it():
- shutil.copyfile(filepath, destination)
- if self.creating:
- do_it()
- else:
- # first check if the file is already present
- if not os.path.exists(destination):
- do_it()
- else:
- # file exists. Let's check if what the instance has is the
- # vainilla old version or not
- old_version_filepath = os.path.join(
- self.old_version_path, 'iepy', 'instantiation', filename)
- if os.path.exists(old_version_filepath) and filecmp.cmp(old_version_filepath, destination):
- # vainilla old version. Let's simply upgrade it
- do_it()
- else:
- # customized file.
- # Check if it's exactly what the new version provides
- if filecmp.cmp(filepath, destination):
- # you have local changes that are 100% new version. Sounds like
- # you made your instance with a nightly built.. dunno, but we'll
- # do nothing, since is not needed.
- return
- # We'll back it up, and later upgrade
- self.preserve_old_file_version_as_copy(destination)
- do_it()
- def prompt(self, msg):
- answer = input("%s (y/n) " % msg).lower().strip()
- while answer not in ['y', 'n']:
- print ('Invalid answer "{}".'.format(answer))
- answer = input("%s (y/n) " % msg).lower().strip()
- return answer == 'y'
- def preserve_old_file_version_as_copy(self, fpath):
- i = 1
- while True:
- back_up_path = fpath + '.backup_{}'.format(i)
- if not os.path.exists(back_up_path):
- break
- i += 1
- shutil.copyfile(fpath, back_up_path)
- print("Backed up your instance version of {} at {}. "
- "Remove it if you don't need it".format(fpath, back_up_path))
- def configure_settings_file(self):
- # Create the settings file
- folder_name = os.path.basename(self.folder_path) # aka iepy instance name
- settings_filepath = os.path.join(self.folder_path, "settings.py")
- def do_it():
- print("Initializing database")
- print("By default, we will create an SQLite database although "
- "it has a very poor performance, specialy with large amounts "
- "of text.\nYou might want to change this in the future.")
- database_name = input("Database name [{}]: ".format(folder_name))
- if not database_name:
- database_name = folder_name
- database_path = os.path.join(self.abs_folder_path, database_name)
- settings_data = get_settings_string(database_path, self.lang)
- with open(settings_filepath, "w") as filehandler:
- filehandler.write(settings_data)
- if self.creating:
- do_it()
- else:
- if self.old_version in ["0.9", "0.9.0", "0.9.1"]:
- old_settings_filepath = os.path.join(
- self.folder_path, "{}_settings.py".format(folder_name)
- )
- shutil.move(old_settings_filepath, settings_filepath)
- with open(settings_filepath, 'a') as fhandler:
- msg = 'Remove line declaring the old IEPY_VERSION above.'
- fhandler.write(
- "IEPY_VERSION = '{}' # {}\n".format(iepy.__version__, msg))
- print ('Patched IEPY_VERSION at {}.'.format(settings_filepath))
- def migrate_db(self):
- # Setup IEPY with the new instance
- os.chdir(self.abs_folder_path)
- iepy.setup(self.abs_folder_path)
- django_command_line(["", "migrate"])
- def create_db_user(self):
- # Setup the database user
- if self.creating:
- print("\nCreating database user")
- django_command_line(["", "createsuperuser"])
- def greetings(self):
- print("\n IEPY instance ready to use at '{}'".format(self.abs_folder_path))
- def get_settings_string(database_path, lang):
- template_settings_filepath = os.path.join(THIS_FOLDER, "settings.py.template")
- with open(template_settings_filepath) as filehandler:
- settings_data = filehandler.read()
- if not database_path.endswith(".sqlite"):
- database_path += ".sqlite"
- chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
- secret_key = get_random_string(50, chars)
- settings_data = settings_data.replace("{SECRET_KEY}", secret_key)
- settings_data = settings_data.replace("{DATABASE_PATH}", database_path)
- settings_data = settings_data.replace("{IEPY_VERSION}", iepy.__version__)
- settings_data = settings_data.replace("{LANG}", lang)
- return settings_data
|