initial commit
This commit is contained in:
		
							parent
							
								
									17d1e7e7a4
								
							
						
					
					
						commit
						f81ba576b6
					
				
					 1 changed files with 341 additions and 0 deletions
				
			
		
							
								
								
									
										341
									
								
								default.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								default.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,341 @@ | ||||||
|  | # The Mac OS Updater | ||||||
|  | ## Install macOS updates from the TUI.  | ||||||
|  | 
 | ||||||
|  | import os; import time as clock | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## app information | ||||||
|  | class app:  | ||||||
|  |     title = "The Mac OS Updater" | ||||||
|  |     description = "Install macOS updates from the TUI." | ||||||
|  |     version = 22.0616 ### YY.MMDD | ||||||
|  | 
 | ||||||
|  | ## localization | ||||||
|  | class texts:  | ||||||
|  |     current_language = "en" | ||||||
|  |      | ||||||
|  |     class screens:  | ||||||
|  |         class titles:  | ||||||
|  |             s_2_0 = 'Download macOS' | ||||||
|  |             s_2_1 = 'Advanced Options' | ||||||
|  |             s_2_2 = 'Beta Update Branch Removal' | ||||||
|  |             s_2_2_1 = 'Disabling Beta Branch Search…' | ||||||
|  |          | ||||||
|  |         class messages:  | ||||||
|  |             s_2_1 = 'Select the beta update branch to be included.' | ||||||
|  |             s_2_2 = 'Do you want to remove the beta update branch when looking for updates? ' | ||||||
|  |             s_2_3 = 'Please read and agree to the lisence before to include the public beta update branch.' | ||||||
|  |             s_2_4 = 'Please read and agree to the lisence before to include the developer beta update branch.' | ||||||
|  |      | ||||||
|  |     class menus:  | ||||||
|  |         main = ['quit', 'refresh', 'install updates', 'download macOS', 'help'] | ||||||
|  |         s_2_0 = ['⬅︎' , 'refresh', 'advanced', 'download: Type an OS version number to download it.'] | ||||||
|  |         s_2_1 = ['⬅︎' , '🚫', 'beta release', 'developer release'] | ||||||
|  |         s_2_2 = ['⬅︎' , 'revert'] | ||||||
|  |         s_2_3 = ['⬅︎' , 'agree'] | ||||||
|  |         s_2_4 = ['⬅︎' , 'agree'] | ||||||
|  |      | ||||||
|  |     class status:  | ||||||
|  |         class checkCompatibility: | ||||||
|  |             checking = 'Checking compatibility…' | ||||||
|  |             done = '' | ||||||
|  |      | ||||||
|  |     class errors:  | ||||||
|  |         class compatibility:  | ||||||
|  |             incompatibility = "There is no use running this outside macOS." | ||||||
|  |             noSoftwareUpdater = "There is no CLI software updater. \nAre you using an old version of macOS?" | ||||||
|  |          | ||||||
|  |         class quit:  | ||||||
|  |             terminationPrompt = "The program refuses to proceed, so it will be closed. \nTo continue, click enter or quit the program yourself." | ||||||
|  |          | ||||||
|  |         class default:  | ||||||
|  |             syntaxerr = "There is a spelling mistake!" | ||||||
|  |             typeerr = "Too bad, something couldn't be converted." | ||||||
|  |             attributeerr = "Something was not linked in properly. " | ||||||
|  | 
 | ||||||
|  |         class screens:  | ||||||
|  |             s_2_2_1: 'Sorry. You are still stuck with the beta branch search enabled. \nPress ^c to go back, and come back to this page to try again.' | ||||||
|  | try:  | ||||||
|  |     ## on Terminal outputs | ||||||
|  |     ### text formatting | ||||||
|  |     class formatting: | ||||||
|  |         clear = '\033[0m' | ||||||
|  |         class color:  | ||||||
|  |             purple = '\033[95m' | ||||||
|  |             cyan = '\033[96m' | ||||||
|  |             cyan_dark = '\033[36m' | ||||||
|  |             blue = '\033[94m' | ||||||
|  |             green = '\033[92m' | ||||||
|  |             yellow = '\033[93m' | ||||||
|  |             red = '\033[91m' | ||||||
|  |         class font: | ||||||
|  |             bold = '\033[1m' | ||||||
|  |             underline = '\033[4m' | ||||||
|  | 
 | ||||||
|  |     ### screen functions | ||||||
|  |     def cls(times = 1): #### to clear screen | ||||||
|  |         times = int(abs(times)); | ||||||
|  |         for _ in range(times): | ||||||
|  |             try:  | ||||||
|  |                 ipy_str = str(type(get_ipython())) | ||||||
|  |                 if 'zmqshell' in ipy_str: from IPython.display import clear_output as clear; clear() | ||||||
|  |                 elif 'terminal' in ipy_str: clear | ||||||
|  |             except NameError: ##### The user is running directly from the terminal, which is expected.   | ||||||
|  |                 import os; return(os.system('clear')) | ||||||
|  | 
 | ||||||
|  |     class info: ### screen messages | ||||||
|  |         def status(message): print(formatting.font.bold + 'ℹ️\t' + formatting.clear + message) | ||||||
|  |         def err(message): print(formatting.font.bold + formatting.color.red + '❌\t' + formatting.clear + formatting.clear + message) | ||||||
|  |         def warning(message): print(formatting.font.bold + formatting.color.yellow + '⚠️\t' + formatting.clear + formatting.clear + message) | ||||||
|  |         def success(message): print(formatting.font.bold + formatting.color.green + '✅\t' + formatting.clear + formatting.clear + message) | ||||||
|  |          | ||||||
|  |         ### terminate with fail function | ||||||
|  |     def fail(message = '', displayAppInformation = True, critical = True):  | ||||||
|  |         import time; | ||||||
|  | 
 | ||||||
|  |         if critical:  | ||||||
|  |             try:  | ||||||
|  |                 if displayAppInformation: operations.display_title_screen(); print('\n') | ||||||
|  |                 info.err(message); input('\n\n' + texts.errors.quit.terminationPrompt); raise KeyboardInterrupt | ||||||
|  |             except KeyboardInterrupt: cls(); exit() | ||||||
|  |         else: print(message) | ||||||
|  |         time.sleep(1); | ||||||
|  | 
 | ||||||
|  |     class user: ## user data | ||||||
|  |         class navigation: ### TLI data | ||||||
|  |             screen = 0  | ||||||
|  |             response = '' | ||||||
|  |              | ||||||
|  |             class window:  | ||||||
|  |                 try:  | ||||||
|  |                     width = int((os.get_terminal_size()).columns) | ||||||
|  |                     lines = int((os.get_terminal_size()).lines) | ||||||
|  |                 except OSError:  | ||||||
|  |                     width = False | ||||||
|  |                     lines = False | ||||||
|  |          | ||||||
|  |         class compatibility: ### for operations.check_compatibility() | ||||||
|  |             isRunningMacOS = (os.name =='posix' and not(os.system('cd /Applications')) and not(os.system('cd /Library')) and not(os.system('cd /System/Library'))) | ||||||
|  |             hasCLIUpdaterInstalled = not(os.system('softwareupdate --help  >/dev/null 2>&1')) #### Check if softwareupdate command is there.  | ||||||
|  |          | ||||||
|  |         class shell:  | ||||||
|  |             try: #### determine Python type, if running in terminal, ipython, or jupyter | ||||||
|  |                 ipy_str = str(type(get_ipython())) | ||||||
|  |                 if 'zmqshell' in ipy_str: pythonType = 'jupyter' | ||||||
|  |                 elif 'terminal' in ipy_str: pythonType = 'ipython' | ||||||
|  |             except: | ||||||
|  |                 pythonType = 'terminal' | ||||||
|  |      | ||||||
|  |     class operations: ## all operations | ||||||
|  |         def display_title_screen(message = ''): ### display title screen and optional message | ||||||
|  |             screenManager.menu.titleBar(app.title); print (app.description + '\nV' + str(app.version)) #### display app information | ||||||
|  |             message = str(message).strip() | ||||||
|  |             if message != '': print(message) #### display message | ||||||
|  | 
 | ||||||
|  |         def check_compatibility(): ### compatibility check | ||||||
|  |             cls() | ||||||
|  |             operations.display_title_screen(texts.status.checkCompatibility.checking) | ||||||
|  | 
 | ||||||
|  |             import os | ||||||
|  |             if user.compatibility.isRunningMacOS:  | ||||||
|  |                 if user.compatibility.hasCLIUpdaterInstalled:  | ||||||
|  |                     return True | ||||||
|  |                 else:  | ||||||
|  |                     fail(texts.errors.compatibility.noSoftwareUpdater); return False | ||||||
|  |             else:  | ||||||
|  |                 fail(texts.errors.compatibility.noSoftwareUpdater); return False | ||||||
|  |          | ||||||
|  |         class software:  | ||||||
|  |             def check_updates():  | ||||||
|  |                 import os | ||||||
|  |                 return(os.system('softwareupdate -l')) | ||||||
|  |             def check_OS_installers():  | ||||||
|  |                 import os | ||||||
|  |                 return(os.system('softwareupdate --list-full-installers')) | ||||||
|  |              | ||||||
|  |             class installer_branch:  | ||||||
|  |                 def none():  | ||||||
|  |                     import os; return(os.system('sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil unenroll')) | ||||||
|  |                  | ||||||
|  |                 def publicBeta():  | ||||||
|  |                     import os; return(os.system('sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil enroll PublicSeed')) | ||||||
|  |                  | ||||||
|  |                 def privateBeta():  | ||||||
|  |                     import os; return(os.system('sudo /System/Library/PrivateFrameworks/Seeding.framework/Versions/A/Resources/seedutil enroll DeveloperSeed')) | ||||||
|  |          | ||||||
|  |     class screenManager: ## TLI | ||||||
|  |          | ||||||
|  |         class graphical:  | ||||||
|  |             def horizontalLine(times = 1): | ||||||
|  |                 times = int(abs(times)) | ||||||
|  |                 if times == 0:  | ||||||
|  |                     times = 1 | ||||||
|  |                  | ||||||
|  |                 for _ in range(times):  | ||||||
|  |                     screenManager.redefineDimensions() | ||||||
|  |                      | ||||||
|  |                     if user.navigation.window.width != False:  | ||||||
|  |                         totalText = '' | ||||||
|  |                         for _ in range(user.navigation.window.width): totalText = totalText + '—' | ||||||
|  |                         print(totalText) | ||||||
|  |                     else: print('') | ||||||
|  |          | ||||||
|  |         class menu: ### for menus | ||||||
|  |             def titleBar(title):  | ||||||
|  |                 title = title.strip() | ||||||
|  |                 titleLength = len(title) | ||||||
|  |                  | ||||||
|  |                 totalText = '' | ||||||
|  |                 if user.navigation.window.width != False:  | ||||||
|  |                     for _ in range(int(((user.navigation.window.width - titleLength)/2)-1)): totalText = totalText + '—' | ||||||
|  |                     totalText = (totalText + ' ') | ||||||
|  |                  | ||||||
|  |                 totalText = (totalText + formatting.font.bold + title + formatting.clear) | ||||||
|  |                  | ||||||
|  |                 if user.navigation.window.width != False:  | ||||||
|  |                     totalText = (totalText + ' ') | ||||||
|  |                     for _ in range(int(((user.navigation.window.width - titleLength)/2)-1)): totalText = totalText + '—' | ||||||
|  |                  | ||||||
|  |                 print(totalText); return(totalText) | ||||||
|  |              | ||||||
|  |             def topMenu(menuShortcut, menuList, displayHorizontalLineBelow = True): #### bottom menu | ||||||
|  |                 entryNumber = 0; displayText = '|' | ||||||
|  |                 for menuItem in menuList:  | ||||||
|  |                     entryNumber = menuList.index(menuItem) | ||||||
|  |                      | ||||||
|  |                     if menuShortcut[entryNumber].strip() == '':  | ||||||
|  |                         displayText = (displayText + menuItem + '|') | ||||||
|  |                     else:  | ||||||
|  |                         displayText = (displayText + formatting.font.bold + menuShortcut[entryNumber] + formatting.clear + ' ' + menuItem + '|') | ||||||
|  |                 print(displayText);  | ||||||
|  |                 if displayHorizontalLineBelow: screenManager.graphical.horizontalLine() | ||||||
|  |              | ||||||
|  |             def inputMenu(menuShortcut, menuList, backSupported = True, passNumbers = False, passAnything = False): #### input | ||||||
|  |                 while True:  | ||||||
|  |                     screenManager.graphical.horizontalLine();  | ||||||
|  |                     try:  | ||||||
|  |                         response = input() | ||||||
|  |                         response = response.strip() | ||||||
|  |                     except KeyboardInterrupt: ##### User cancelled.  | ||||||
|  |                         if backSupported: return -1;  | ||||||
|  |                         else: print("", end="\r") ##### Loop again.  | ||||||
|  |                     else:  | ||||||
|  |                         if response in menuShortcut or response in menuList or passAnything:  | ||||||
|  |                             return(response) | ||||||
|  |                         elif passNumbers:  | ||||||
|  |                             try: response = float(response) | ||||||
|  |                             except: print("", end="\r") | ||||||
|  |                             else: return(response) | ||||||
|  |                         else: print("", end="\r") | ||||||
|  |              | ||||||
|  |             def promptMenu(promptTitle, promptDescription, promptOptions, promptShortcuts, canCancel = True, extraInputAllowed = False, numbersAllowed = False):  | ||||||
|  |                 screenManager.menu.titleBar(promptTitle.strip()) | ||||||
|  |                  | ||||||
|  |                 print(promptDescription) | ||||||
|  |                  | ||||||
|  |                 if user.navigation.window.lines != False:  | ||||||
|  |                     for _ in range((user.navigation.window.lines)/4): print('') | ||||||
|  |                 else: print('\n\n') | ||||||
|  |                      | ||||||
|  |                 screenManager.menu.topMenu(promptShortcuts, promptOptions) | ||||||
|  |                  | ||||||
|  |                 user.navigation.response = screenManager.menu.inputMenu(promptShortcuts, promptOptions, canCancel, numbersAllowed, extraInputAllowed) | ||||||
|  |                 return(user.navigation.response) | ||||||
|  |              | ||||||
|  |         def redefineDimensions():  | ||||||
|  |             try: user.navigation.window.width = int((os.get_terminal_size()).columns) | ||||||
|  |             except OSError: user.navigation.window.width = False | ||||||
|  | 
 | ||||||
|  |             try: user.navigation.window.lines = int((os.get_terminal_size()).lines) | ||||||
|  |             except OSError: user.navigation.window.lines = False | ||||||
|  |          | ||||||
|  |         def do():  | ||||||
|  |             while user.navigation.screen >= 0:  | ||||||
|  |                 cls(); screenManager.redefineDimensions() | ||||||
|  | 
 | ||||||
|  |                 if user.navigation.screen < 1: ### when opened | ||||||
|  |                     if user.navigation.screen == 0:  | ||||||
|  |                         operations.display_title_screen() | ||||||
|  |                         clock.sleep(1) | ||||||
|  |                         user.navigation.screen = 0.1 | ||||||
|  | 
 | ||||||
|  |                     elif user.navigation.screen == 0.1:  | ||||||
|  |                         if operations.check_compatibility(): user.navigation.screen = 1 | ||||||
|  | 
 | ||||||
|  |                 elif user.navigation.screen < 2:  | ||||||
|  |                     if user.navigation.screen == 1:  | ||||||
|  |                         menuShortcut = ['^c', 'r', 'i', 'd', '?'] | ||||||
|  |                          | ||||||
|  |                         screenManager.menu.titleBar(app.title); screenManager.menu.topMenu(menuShortcut, texts.menus.main) | ||||||
|  |                          | ||||||
|  |                         operations.software.check_updates() | ||||||
|  |                          | ||||||
|  |                         user.navigation.response = screenManager.menu.inputMenu(menuShortcut, texts.menus.main) | ||||||
|  |                          | ||||||
|  |                         if user.navigation.response == -1 or user.navigation.response == '^c':  | ||||||
|  |                             user.navigation.screen = -1 | ||||||
|  |                         elif user.navigation.response == 'd':  | ||||||
|  |                             user.navigation.screen = 2 | ||||||
|  |                              | ||||||
|  |                 elif user.navigation.screen < 3: ### full installer downloader, necessary and recommended to upgrade the OS | ||||||
|  |                     if user.navigation.screen == 2:  | ||||||
|  |                         menuShortcut = ['^c', 'r', 'A', ''] | ||||||
|  |                          | ||||||
|  |                         screenManager.menu.titleBar(texts.screens.titles.s_2_0); screenManager.menu.topMenu(menuShortcut, texts.menus.s_2_0) | ||||||
|  |                          | ||||||
|  |                         operations.software.check_OS_installers() | ||||||
|  |                          | ||||||
|  |                         user.navigation.response = screenManager.menu.inputMenu(menuShortcut, texts.menus.s_2_0, True, True) | ||||||
|  |                          | ||||||
|  |                         if user.navigation.response == -1 or user.navigation.response == '^c':  | ||||||
|  |                             user.navigation.screen = 1 | ||||||
|  |                              | ||||||
|  |                         elif user.navigation.response == 'A':  | ||||||
|  |                             user.navigation.screen = 2.1 | ||||||
|  |                              | ||||||
|  |                     elif user.navigation.screen == 2.1:  | ||||||
|  |                         menuShortcut = ['^c', 'n', 'b', 'D'] | ||||||
|  |                          | ||||||
|  |                         screenManager.menu.promptMenu(texts.screens.titles.s_2_1, texts.screens.messages.s_2_1, texts.menus.s_2_1, menuShortcut) | ||||||
|  |                          | ||||||
|  |                         if user.navigation.response == -1 or user.navigation.response == '^c':  | ||||||
|  |                             user.navigation.screen = 2 | ||||||
|  |                          | ||||||
|  |                         elif user.navigation.response == 'n' or user.navigation.response == '🚫':  | ||||||
|  |                             user.navigation.screen = 2.2 | ||||||
|  |                      | ||||||
|  |                     elif user.navigation.screen == 2.2:  | ||||||
|  |                         menuShortcut = ['^c', ''] | ||||||
|  |                          | ||||||
|  |                         screenManager.menu.promptMenu(texts.screens.titles.s_2_2, texts.screens.messages.s_2_2, texts.menus.s_2_2, menuShortcut) | ||||||
|  |                          | ||||||
|  |                         if user.navigation.response == -1 or user.navigation.response == '^c':  | ||||||
|  |                             user.navigation.screen = 2.1 | ||||||
|  |                          | ||||||
|  |                         elif user.navigation.response == '' or user.navigation.response == 'revert':  | ||||||
|  |                             user.navigation.screen == 2.21 | ||||||
|  |                              | ||||||
|  |                     elif user.navigation.screen == 2.21:  | ||||||
|  |                         screenManager.menu.titleBar(texts.screens.titles.s_2_2_1);  | ||||||
|  |                          | ||||||
|  |                         if (operations.software.installer_branch.none()):  | ||||||
|  |                             try:  | ||||||
|  |                                 info.err(texts.errors.screens.s_2_2_1) | ||||||
|  |                             except KeyboardInterrupt:  | ||||||
|  |                                 user.navigation.screen = 2.1 | ||||||
|  |                         else:  | ||||||
|  |                             user.navigation.screen = 2.1 | ||||||
|  |                          | ||||||
|  |             if user.navigation.screen == -1:  | ||||||
|  |                 cls() | ||||||
|  |          | ||||||
|  |     def main():  | ||||||
|  |         screenManager.do() | ||||||
|  |      | ||||||
|  |     main() | ||||||
|  | 
 | ||||||
|  | except SyntaxError as e: fail(texts.errors.default.syntaxerr + '\n' + str(e)) | ||||||
|  | except NameError as e: fail(texts.errors.default.syntaxerr + '\n' + str(e)) | ||||||
|  | except IndentationError as e: fail(texts.errors.default.syntaxerr + '\n' + str(e)) | ||||||
|  | except TypeError as e: fail(texts.errors.default.typeerr + '\n' + str(e)) | ||||||
|  | except AttributeError as e: fail(texts.errors.default.attributeerr + '\n' + str(e)) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue