def __init__(self, input=sys.stdin, output=sys.stdout, enable_color=True, wrap_width=80, record_tags=False, fallback_wrap=80): try: Prompt.__init__(self, input=input, output=output, enable_color=enable_color, wrap_width=wrap_width, record_tags=record_tags) except IOError: print "\nUnable to access tty size, continuing with wrap width.\n" Prompt.__init__(self, input=input, output=output, enable_color=enable_color, wrap_width=fallback_wrap, record_tags=record_tags) # Shadowed for another alternative to referencing it self.ABORT = ABORT
def __init__(self, stream_file=STREAM_FILE, prod_db_name=PULP_DATABASE_NAME, tmp_db_name=TEMP_DATABASE_NAME, v1_backup_db_name=V1_BACKUP_DATABASE_NAME, backup_v1_db=False, upgrade_db=True, db_seeds=DEFAULT_SEEDS, db_upgrade_calls=DB_UPGRADE_CALLS, upgrade_files=True, files_upgrade_calls=FILES_UPGRADE_CALLS, install_db=True, clean=True): self.stream_file = stream_file self.prod_db_name = prod_db_name self.tmp_db_name = tmp_db_name self.v1_backup_db_name = v1_backup_db_name self.backup_v1_db = backup_v1_db self.upgrade_db = upgrade_db self.db_seeds = db_seeds self.db_upgrade_calls = db_upgrade_calls self.upgrade_files = upgrade_files self.files_upgrade_calls = files_upgrade_calls self.install_db = install_db self.clean = clean self.prompt = Prompt()
def __init__(self, input=sys.stdin, output=sys.stdout, enable_color=True, wrap_width=80, record_tags=False): Prompt.__init__(self, input=input, output=output, enable_color=enable_color, wrap_width=wrap_width, record_tags=record_tags) # Shadowed for another alternative to referencing it self.ABORT = ABORT
def content_applicability2(): repo_criteria = { "sort": [["id", "ascending"]], "filters": { "id": { "$in": ["test-repo", "zoo"] } } } options = { "repo_criteria": repo_criteria, } p = Prompt() pprint( "/pulp/api/v2/repositories/actions/content/regenerate_applicability/") p.write('\repo_criteria -', color=COLOR_LIGHT_BLUE) pprint(repo_criteria) p.write('') result = pic.POST( '/pulp/api/v2/repositories/actions/content/regenerate_applicability/', options) pause(p) p.write('\nresult -', color=COLOR_LIGHT_BLUE) pprint(result) p.write('')
def content_applicability1(): consumer_criteria = { "sort": [["id", "ascending"]], "filters": { "id": { "$in": ["lemonade", "sunflower", "voyager"] } } } options = { "consumer_criteria": consumer_criteria, } p = Prompt() pprint("/pulp/api/v2/consumers/actions/content/regenerate_applicability/") p.write('\nconsumer_criteria -', color=COLOR_LIGHT_BLUE) pprint(consumer_criteria) p.write('') result = pic.POST( '/pulp/api/v2/consumers/actions/content/regenerate_applicability/', options) pause(p) p.write('\nresult -', color=COLOR_LIGHT_BLUE) pprint(result) p.write('')
def spinner_demo(): p = Prompt() spinner = Spinner(p) total = 10 for i in range(0, total): spinner.next() time.sleep(.25) spinner.clear() p.write('Completed first spinner example') p.write('') sequence = '! @ # $ %'.split() spinner = Spinner(p, sequence=sequence, left_tick='{', right_tick='}', in_progress_color=COLOR_LIGHT_YELLOW, completed_color=COLOR_LIGHT_GREEN) total = 10 for i in range(0, total): finished = i == (total - 1) spinner.next(finished=finished, message='Message: %s' % i) time.sleep(.25) p.write('Completed second spinner example') p.write('')
def write(self, content, new_line=True, center=False, color=None, tag=None, skip_wrap=False): content = encode_unicode(content) Prompt.write(self, content, new_line, center, color, tag, skip_wrap)
def spinner_demo(): p = Prompt() spinner = Spinner(p) total = 10 for i in range(0, total): next(spinner) time.sleep(.25) spinner.clear() p.write('Completed first spinner example') p.write('') sequence = '! @ # $ %'.split() spinner = Spinner(p, sequence=sequence, left_tick='{', right_tick='}', in_progress_color=COLOR_LIGHT_YELLOW, completed_color=COLOR_LIGHT_GREEN) total = 10 for i in range(0, total): finished = i == (total - 1) spinner.next(finished=finished, message='Message: %s' % i) time.sleep(.25) p.write('Completed second spinner example') p.write('')
def main(): p = Prompt() pic.connect() pic.LOG_BODIES = True title(p, "Consumer Applicability Generation APIs Demo") pause(p) p.write("\n------------------------------------------------------------------------\n") title(p, "Demo with consumer_criteria") content_applicability1() title(p, "Demo with repo_criteria") content_applicability2()
def main(): p = Prompt() pic.connect() pic.LOG_BODIES = True title(p, 'Consumer Applicability Generation APIs Demo') pause(p) p.write('\n------------------------------------------------------------------------\n') title(p, 'Demo with consumer_criteria') content_applicability1() title(p, 'Demo with repo_criteria') content_applicability2()
def content_applicability2(): repo_criteria = {"sort": [["id", "ascending"]], "filters": {"id": {"$in": ["test-repo", "zoo"]}}} options = {"repo_criteria": repo_criteria} p = Prompt() pprint("/pulp/api/v2/repositories/actions/content/regenerate_applicability/") p.write("\repo_criteria -", color=COLOR_LIGHT_BLUE) pprint(repo_criteria) p.write("") result = pic.POST("/pulp/api/v2/repositories/actions/content/regenerate_applicability/", options) pause(p) p.write("\nresult -", color=COLOR_LIGHT_BLUE) pprint(result) p.write("")
def test_get_password(self, mock_getpass): # Setup mock_getpass.return_value = 'letmein' prompt = Prompt() password = prompt._get_password('Password: '******'letmein') mock_getpass.assert_called_once_with('Password: ', stream=prompt.output)
def content_applicability1(): consumer_criteria = { "sort": [["id", "ascending"]], "filters": {"id": {"$in": ["lemonade", "sunflower", "voyager"]}}} options = {"consumer_criteria":consumer_criteria, } p = Prompt() pprint("/pulp/api/v2/consumers/actions/content/regenerate_applicability/") p.write('\nconsumer_criteria -', color=COLOR_LIGHT_BLUE) pprint(consumer_criteria) p.write('') result = pic.POST('/pulp/api/v2/consumers/actions/content/regenerate_applicability/', options) pause(p) p.write('\nresult -', color=COLOR_LIGHT_BLUE) pprint(result) p.write('')
def test_color(self): """ Tests the color call correctly wraps the text with the correct markers. """ # Test prompt = Prompt() colored = prompt.color('Hulk', okaara.prompt.COLOR_GREEN) # Verify expected = okaara.prompt.COLOR_GREEN + 'Hulk' + okaara.prompt.COLOR_WHITE self.assertEqual(colored, expected)
def test_prompt_password(self, mock_getpass): """ Make sure this correctly passes through to getpass one way or another """ # Setup mock_getpass.return_value = 'letmein' prompt = Prompt() password = prompt.prompt_password('Password: '******'letmein') self.assertEqual(mock_getpass.call_count, 1) self.assertEqual(mock_getpass.call_args[0][0], 'Password: ')
def test_read_interrupt(self): """ Tests that having read catch interrupt correctly returns the abort code. """ # Setup script = Script([Script.INTERRUPT]) prompt = Prompt(input=script) # Test r = prompt.read('Thor', interruptable=True) # Verify self.assertEqual(ABORT, r)
def test_wrap_long_wrap(self): """ Tests that chop correctly handles data shorter than the chop length. """ # Setup prompt = Prompt() # Test wrapped = prompt.wrap('Green Goblin', 100) # Verify pieces = wrapped.split('\n') self.assertEqual(1, len(pieces))
def test_wrap_short_wrap(self): """ Tests that chop correctly handled data longer than the chop length. """ # Setup prompt = Prompt() # Test wrapped = prompt.wrap('Spiderman', 3) # Verify pieces = wrapped.split('\n') self.assertEqual(3, len(pieces))
def test_wrap_with_none(self): """ Tests that chop with a None wrap width doesn't crash. """ # Setup prompt = Prompt() # Test wrapped = prompt.wrap('Electro', None) # Verify pieces = wrapped.split('\n') self.assertEqual(1, len(pieces))
def test_write_color(self): """ Tests the color functionality built into write works. """ # Setup recorder = Recorder() prompt = Prompt(output=recorder) # Test prompt.write('Hulk', color=okaara.prompt.COLOR_RED, new_line=False) # Verify expected = okaara.prompt.COLOR_RED + 'Hulk' + okaara.prompt.COLOR_WHITE self.assertEqual(recorder.lines[1], expected)
def test_wrap_smart_split(self): """ Tests smart wrapping to not break words. """ # Setup text = 'abc def ghikl mno pqrs' prompt = Prompt() # Test wrapped = prompt.wrap(text, 5) # Verify expected = 'abc\ndef\nghikl\nmno\npqrs' self.assertEqual(expected, wrapped)
def test_prompt_allow_empty(self): """ Tests that a prompt will accept empty and not error. """ # Setup lines = ['', 'not used'] script = Script(lines) prompt = Prompt(input=script) # Test entered = prompt.prompt('Question', allow_empty=True) # Verify self.assertEqual(1, len(script.lines)) self.assertEqual('', entered)
def test_prompt_no_empty(self): """ Tests that a prompt that does not allow empty values re-prompts the user and does nto error. """ # Setup lines = ['', 'value'] script = Script(lines) prompt = Prompt(input=script) # Test entered = prompt.prompt('Question') # Verify self.assertEqual(0, len(script.lines)) self.assertEqual('value', entered)
def test_prompt_menu(self): """ Basic tests for prompting a menu of items and selecting a valid one. """ # Setup lines = ['1', '2'] script = Script(lines) prompt = Prompt(input=script) items = ['a', 'b', 'c'] # Test index = prompt.prompt_menu('Question', items) # Verify self.assertEqual(0, index) self.assertEqual(1, len(script.lines))
def test_write_with_wrap(self): """ Tests using an auto-wrap value correctly wraps text. """ # Setup recorder = Recorder() prompt = Prompt(output=recorder, wrap_width=10) # Test prompt.write('-' * 20) # Verify written_lines = recorder.lines[1].split('\n') self.assertEqual(3, len(written_lines)) self.assertEqual('-' * 10, written_lines[0]) self.assertEqual('-' * 10, written_lines[1]) self.assertEqual('', written_lines[2])
def progress_bar_demo(): p = Prompt() pb = ProgressBar(p) total = 21 for i in range(0, total + 1): message = 'Step: %d of %d' % (i, total) if i % 3 is 0: message += '\nSecond line in message' if i % 6 is 0: message += '\nThird line in message' pb.render(i, total, message) time.sleep(.25) p.write('Completed first progress bar example') p.write('') pb = ProgressBar(p, fill='*', left_tick='-<', right_tick='>-', show_trailing_percentage=False, in_progress_color=COLOR_LIGHT_YELLOW, completed_color=COLOR_LIGHT_GREEN) total = 17 for i in range(0, total + 1): pb.render(i, total) time.sleep(.1) p.write('Completed second progress bar example') p.write('') pb = ProgressBar(p) items = 'a b c d e f g h i j k l m n o p'.split() wrapped = pb.iterator(items, message_func=lambda x: 'Generated for item: %s' % x) for w in wrapped: # Do important stuff but don't worry about progress bar time.sleep(.3) p.write('Completed wrapped iteration through progress bar') p.write('')
def threaded_spinner_demo(): p = Prompt() s = ThreadedSpinner(p, refresh_seconds=.1) p.write( 'Starting threaded spinner, spinner should keep moving while this thread sleeps' ) s.start() time.sleep(3) # spinner should keep moving s.stop() p.write('Threaded spinner stopped') p.write('') s = ThreadedSpinner(p, refresh_seconds=.1, timeout_seconds=2) p.write( 'Starting threaded spinner, spinner will time out while the execution thread is working' ) s.start() time.sleep(3) # spinner should keep moving s.stop() p.write('Threaded spinner timed out') p.write('') s = ThreadedSpinner(p, refresh_seconds=.1) p.write('Starting threaded spinner with auto-clear') s.start() time.sleep(3) # spinner should keep moving s.stop(clear=True) p.write('Threaded spinner stopped') p.write('') s = ThreadedSpinner(p, refresh_seconds=3) p.write('Starting threaded spinner reuse test') s.start() time.sleep(.01) s.stop() p.write('Stopped 1') s.start() time.sleep(.01) s.stop() p.write('Stopped 2')
def __init__(self, prompt=None, auto_render_menu=False, include_long_triggers=True): """ Creates an empty shell. At least one screen must be added to the shell before it is used. :param prompt: specifies a prompt object to use for reading/writing to the console; if not specified will default to L{Prompt} :type prompt: L{Prompt} :param auto_render_menu: if True, the menu will automatically be rendered after the execution of each menu item; defaults to False :type auto_render_menu: bool :param include_long_triggers: if True, the long versions of default triggers will be added, if False only single-character triggers will be added; defaults to True :type include_long_triggers: bool """ self.home_screen = None self.current_screen = None self.previous_screen = None self.screens = {} self.auto_render_menu = auto_render_menu # Set the default prompt prefix to substitute in the current screen ID self.prompt_prefix = '($s) => ' # Create a default prompt if one was not explicitly specified self.prompt = prompt or Prompt() # Create the shell-level menu; these can be changed before the shell is run previous_triggers = ['<'] home_triggers = ['^'] quit_triggers = ['q'] help_triggers = ['?'] clear_triggers = ['/'] if include_long_triggers: home_triggers.append('home') quit_triggers.append('quit') quit_triggers.append('exit') help_triggers.append('help') clear_triggers.append('clear') self.shell_menu_items = {} self.ordered_menu_items = [ ] # kinda ghetto, need to replace with ordered dict for menu_items self.add_menu_item( MenuItem(home_triggers, _('move to the home screen'), self.home)) self.add_menu_item( MenuItem(previous_triggers, _('move to the previous screen'), self.previous)) self.add_menu_item( MenuItem(help_triggers, _('display help'), self.render_menu)) self.add_menu_item( MenuItem(clear_triggers, _('clears the screen'), self.clear_screen)) self.add_menu_item(MenuItem(quit_triggers, _('exit'), self.stop))
class Upgrader(object): """ :ivar stream_file: full location to the file containing stream information; the file does not necessarily have to exist :type stream_file: str :ivar upgrade_db: configures whether or not the DB upgrade scripts will be run; if this is False, the clean step will be skipped regardless of its configured value :type upgrade_db: bool :ivar db_upgrade_calls: dictates which database upgrade steps will be performed; see DB_UPGRADE_CALLS comment above for a description of the entries. :type db_upgrade_calls: list :ivar db_seeds: seeds for accessing MongoDB :type db_seeds: str :ivar upgrade_files: configures whether or not the filesystem upgrade scripts will be run; if this is False, the clean step will be skipped regardless of its configured value :type upgrade_files: bool :ivar files_upgrade_calls: dictates which filesystem upgrade steps will be performed; see FILES_UPGRADE_CALLS for a description of the entries :type files_upgrade_calls: list :ivar install_db: dictates if the temporary database created by the build DB step will replace the production database and delete the temp :type install_db: bool :ivar clean: dictates if the filesystem clean up operations will be run :type clean: bool """ def __init__(self, stream_file=STREAM_FILE, prod_db_name=PULP_DATABASE_NAME, tmp_db_name=TEMP_DATABASE_NAME, v1_backup_db_name=V1_BACKUP_DATABASE_NAME, backup_v1_db=False, upgrade_db=True, db_seeds=DEFAULT_SEEDS, db_upgrade_calls=DB_UPGRADE_CALLS, upgrade_files=True, files_upgrade_calls=FILES_UPGRADE_CALLS, install_db=True, clean=True): self.stream_file = stream_file self.prod_db_name = prod_db_name self.tmp_db_name = tmp_db_name self.v1_backup_db_name = v1_backup_db_name self.backup_v1_db = backup_v1_db self.upgrade_db = upgrade_db self.db_seeds = db_seeds self.db_upgrade_calls = db_upgrade_calls self.upgrade_files = upgrade_files self.files_upgrade_calls = files_upgrade_calls self.install_db = install_db self.clean = clean self.prompt = Prompt() def upgrade(self): """ Performs the upgrade process if the installation qualifies to be upgraded. :return: nothing if the upgrade was successful :raise InvalidStepReportException: if any of the steps does not properly indicate its success or failure; should only occur during development :raise StepException: if a step raises an error or indicates it failed """ if not self._is_v1(): self._print(_('Pulp installation is already upgraded to the latest version')) self._print('') return if not self.upgrade_db: self._print(_('Skipping Database Upgrade')) self._print('') else: self._upgrade_database() if not self.upgrade_files: self._print(_('Skipping Filesystem Upgrade')) self._print('') else: self._upgrade_files() if not self.install_db: self._print(_('Skipping v2 Database Installation')) self._print('') else: self._install() # The files are used in both the upgrade DB and upgrade files step, so # if either are skipped, assume they'll be run again in the future # and automatically skip the clean if not self.clean or not self.upgrade_files or not self.upgrade_db: self._print(_('Skipping v1 Filesystem Clean Up')) self._print('') else: self._clean() self._drop_stream_flag() def _upgrade_database(self): """ Runs all configured upgrade scripts for handling the database. """ self._print(_('= Upgrading Database =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for db_call, description in self.db_upgrade_calls: self._print(_('Upgrading: %(d)s') % {'d' : description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = db_call(v1_database, tmp_database) except: spinner.stop() spinner.clear() # temporary until okaara supports this raise spinner.stop() spinner.clear() # temporary until okaara supports this if report is None or report.success is None: # This should only happen during development if the script writer # didn't properly configure the report and must be fixed before # release self._print(_('Database upgrade script did not indicate the result of the step')) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _upgrade_files(self): """ Runs all configured upgrade scripts for handling the filesystem. """ self._print(_('= Upgrading Pulp Files =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for upgrade_call, description in self.files_upgrade_calls: self._print(_('Upgrading: %(d)s') % {'d' : description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = upgrade_call(v1_database, tmp_database) except: spinner.stop() spinner.clear() raise spinner.stop() spinner.clear() if report is None or report.success is None: # This should only happen during development if the script writer # didn't properly configure the report and must be fixed before # release self._print(_('Filesystem upgrade script did not indicate the result of the step')) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _install(self): # Backup if self.backup_v1_db: self._print(_('Backing up the v1 database to %(db)s') % {'db' : self.v1_backup_db_name}) spinner = ThreadedSpinner(self.prompt) spinner.start() self._backup_v1() spinner.stop() spinner.clear() else: self._print(_('The v1 database will not be backed up')) self.prompt.write('') # Install self._print(_('Installing the v2 Database')) spinner = ThreadedSpinner(self.prompt) spinner.start() self._install_v2() spinner.stop() spinner.clear() self.prompt.write('') # Clean Up self._print(_('Deleting v2 Temporary Database')) spinner = ThreadedSpinner(self.prompt) spinner.start() self._cleanup() spinner.stop() spinner.clear() self.prompt.write('') def _clean(self): self._print(_('= Clean Up =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for upgrade_call, description in CLEAN_UPGRADE_CALLS: self._print(_('Cleaning: %(d)s') % {'d' : description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = upgrade_call(v1_database, tmp_database) except: spinner.stop() spinner.clear() raise spinner.stop() spinner.clear() if report is None or report.success is None: self._print(_('Clean upgrade script did not indicate the result of the step')) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _drop_stream_flag(self): """ Creates the stream flag that is used to prevent multiple runs of the upgrade """ f = open(self.stream_file, 'w') f.write('v2') f.close() # -- utilities ---------------------------------------------------------------- def _connection(self): connection = Connection(self.db_seeds) return connection def _database(self, db_name): connection = self._connection() database = getattr(connection, db_name) database.add_son_manipulator(NamespaceInjector()) database.add_son_manipulator(AutoReference(database)) return database def _backup_v1(self): connection = self._connection() connection.copy_database(self.prod_db_name, self.v1_backup_db_name) def _install_v2(self): connection = self._connection() connection.drop_database(self.prod_db_name) connection.copy_database(self.tmp_db_name, self.prod_db_name) def _cleanup(self): connection = self._connection() connection.drop_database(self.tmp_db_name) def _print(self, line): _LOG.info(line) self.prompt.write(line) def _print_report_data(self, title, items): if len(items) > 0: self._print(title) for i in items: self._print(' %s' % i) def _is_v1(self): """ Returns whether or not the current installation is a v1 stream build. :return: True if the installation is a v1 build, False otherwise :rtype: bool """ # Eventually this will check the contents of that file, but for now the # quickest solution is just to check its existence result = not os.path.exists(self.stream_file) return result
def threaded_spinner_demo(): p = Prompt() s = ThreadedSpinner(p, refresh_seconds=.1) p.write('Starting threaded spinner, spinner should keep moving while this thread sleeps') s.start() time.sleep(3) # spinner should keep moving s.stop() p.write('Threaded spinner stopped') p.write('') s = ThreadedSpinner(p, refresh_seconds=.1, timeout_seconds=2) p.write('Starting threaded spinner, spinner will time out while the execution thread is working') s.start() time.sleep(3) # spinner should keep moving s.stop() p.write('Threaded spinner timed out') p.write('') s = ThreadedSpinner(p, refresh_seconds=.1) p.write('Starting threaded spinner with auto-clear') s.start() time.sleep(3) # spinner should keep moving s.stop(clear=True) p.write('Threaded spinner stopped') p.write('') s = ThreadedSpinner(p, refresh_seconds=3) p.write('Starting threaded spinner reuse test') s.start() time.sleep(.01) s.stop() p.write('Stopped 1') s.start() time.sleep(.01) s.stop() p.write('Stopped 2')
class Upgrader(object): """ :ivar stream_file: full location to the file containing stream information; the file does not necessarily have to exist :type stream_file: str :ivar upgrade_db: configures whether or not the DB upgrade scripts will be run; if this is False, the clean step will be skipped regardless of its configured value :type upgrade_db: bool :ivar db_upgrade_calls: dictates which database upgrade steps will be performed; see DB_UPGRADE_CALLS comment above for a description of the entries. :type db_upgrade_calls: list :ivar db_seeds: seeds for accessing MongoDB :type db_seeds: str :ivar upgrade_files: configures whether or not the filesystem upgrade scripts will be run; if this is False, the clean step will be skipped regardless of its configured value :type upgrade_files: bool :ivar files_upgrade_calls: dictates which filesystem upgrade steps will be performed; see FILES_UPGRADE_CALLS for a description of the entries :type files_upgrade_calls: list :ivar install_db: dictates if the temporary database created by the build DB step will replace the production database and delete the temp :type install_db: bool :ivar clean: dictates if the filesystem clean up operations will be run :type clean: bool """ def __init__(self, stream_file=STREAM_FILE, prod_db_name=PULP_DATABASE_NAME, tmp_db_name=TEMP_DATABASE_NAME, v1_backup_db_name=V1_BACKUP_DATABASE_NAME, backup_v1_db=False, upgrade_db=True, db_seeds=DEFAULT_SEEDS, db_upgrade_calls=DB_UPGRADE_CALLS, upgrade_files=True, files_upgrade_calls=FILES_UPGRADE_CALLS, install_db=True, clean=True): self.stream_file = stream_file self.prod_db_name = prod_db_name self.tmp_db_name = tmp_db_name self.v1_backup_db_name = v1_backup_db_name self.backup_v1_db = backup_v1_db self.upgrade_db = upgrade_db self.db_seeds = db_seeds self.db_upgrade_calls = db_upgrade_calls self.upgrade_files = upgrade_files self.files_upgrade_calls = files_upgrade_calls self.install_db = install_db self.clean = clean self.prompt = Prompt() def upgrade(self): """ Performs the upgrade process if the installation qualifies to be upgraded. :return: nothing if the upgrade was successful :raise InvalidStepReportException: if any of the steps does not properly indicate its success or failure; should only occur during development :raise StepException: if a step raises an error or indicates it failed """ if not self._is_v1(): self._print( _('Pulp installation is already upgraded to the latest version' )) self._print('') return if not self.upgrade_db: self._print(_('Skipping Database Upgrade')) self._print('') else: self._upgrade_database() if not self.upgrade_files: self._print(_('Skipping Filesystem Upgrade')) self._print('') else: self._upgrade_files() if not self.install_db: self._print(_('Skipping v2 Database Installation')) self._print('') else: self._install() # The files are used in both the upgrade DB and upgrade files step, so # if either are skipped, assume they'll be run again in the future # and automatically skip the clean if not self.clean or not self.upgrade_files or not self.upgrade_db: self._print(_('Skipping v1 Filesystem Clean Up')) self._print('') else: self._clean() self._drop_stream_flag() def _upgrade_database(self): """ Runs all configured upgrade scripts for handling the database. """ self._print(_('= Upgrading Database =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for db_call, description in self.db_upgrade_calls: self._print(_('Upgrading: %(d)s') % {'d': description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = db_call(v1_database, tmp_database) except: spinner.stop(clear=True) raise spinner.stop(clear=True) if report is None or report.success is None: # This should only happen during development if the script writer # didn't properly configure the report and must be fixed before # release self._print( _('Database upgrade script did not indicate the result of the step' )) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _upgrade_files(self): """ Runs all configured upgrade scripts for handling the filesystem. """ self._print(_('= Upgrading Pulp Files =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for upgrade_call, description in self.files_upgrade_calls: self._print(_('Upgrading: %(d)s') % {'d': description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = upgrade_call(v1_database, tmp_database) except: spinner.stop(clear=True) raise spinner.stop(clear=True) if report is None or report.success is None: # This should only happen during development if the script writer # didn't properly configure the report and must be fixed before # release self._print( _('Filesystem upgrade script did not indicate the result of the step' )) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _install(self): # Backup if self.backup_v1_db: self._print( _('Backing up the v1 database to %(db)s') % {'db': self.v1_backup_db_name}) spinner = ThreadedSpinner(self.prompt) spinner.start() self._backup_v1() spinner.stop(clear=True) else: self._print(_('The v1 database will not be backed up')) self.prompt.write('') # Install self._print(_('Installing the v2 Database')) spinner = ThreadedSpinner(self.prompt) spinner.start() self._install_v2() spinner.stop(clear=True) self.prompt.write('') # Clean Up self._print(_('Deleting v2 Temporary Database')) spinner = ThreadedSpinner(self.prompt) spinner.start() self._cleanup() spinner.stop(clear=True) self.prompt.write('') def _clean(self): self._print(_('= Clean Up =')) v1_database = self._database(self.prod_db_name) tmp_database = self._database(self.tmp_db_name) for upgrade_call, description in CLEAN_UPGRADE_CALLS: self._print(_('Cleaning: %(d)s') % {'d': description}) spinner = ThreadedSpinner(self.prompt) spinner.start() try: report = upgrade_call(v1_database, tmp_database) except: spinner.stop(clear=True) raise spinner.stop(clear=True) if report is None or report.success is None: self._print( _('Clean upgrade script did not indicate the result of the step' )) raise InvalidStepReportException() if report.success: self._print_report_data(_('Messages'), report.messages) self._print_report_data(_('Warnings'), report.warnings) else: self._print_report_data(_('Warnings'), report.warnings) self._print_report_data(_('Errors'), report.errors) raise StepException(description) self.prompt.write('') def _drop_stream_flag(self): """ Creates the stream flag that is used to prevent multiple runs of the upgrade """ f = open(self.stream_file, 'w') f.write('v2') f.close() # -- utilities ---------------------------------------------------------------- def _connection(self): connection = Connection(self.db_seeds) return connection def _database(self, db_name): connection = self._connection() database = getattr(connection, db_name) database.add_son_manipulator(NamespaceInjector()) database.add_son_manipulator(AutoReference(database)) return database def _backup_v1(self): connection = self._connection() connection.copy_database(self.prod_db_name, self.v1_backup_db_name) def _install_v2(self): connection = self._connection() connection.drop_database(self.prod_db_name) connection.copy_database(self.tmp_db_name, self.prod_db_name) def _cleanup(self): connection = self._connection() connection.drop_database(self.tmp_db_name) def _print(self, line): _LOG.info(line) self.prompt.write(line) def _print_report_data(self, title, items): if len(items) > 0: self._print(title) for i in items: self._print(' %s' % i) def _is_v1(self): """ Returns whether or not the current installation is a v1 stream build. :return: True if the installation is a v1 build, False otherwise :rtype: bool """ # Eventually this will check the contents of that file, but for now the # quickest solution is just to check its existence result = not os.path.exists(self.stream_file) return result
def test_py26_behavior(self): prompt = Prompt() password = prompt._get_password('Password: '******'letmein')