diff --git a/CHANGELOG.md b/CHANGELOG.md index 7723741ba..fc06254a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-01-10 +## Update for 2023-01-11 Following-up on a major release, here is a lot more functionality in new Control module and FaceID & IPAdapter modules Plus welcome additions to UI accessibility and flexibility of deployment @@ -57,6 +57,8 @@ And it also includes fixes for all reported issues so far - enable use via api, thanks @trojaner - **Improvements** - **ui** + - check version and **update** SD.Next via UI + simply go to: settings -> update - globally configurable **font size** will dynamically rescale ui depending on settings -> user interface - built-in **themes** can be changed on-the-fly diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 70d95d394..6e649def2 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 70d95d3943f0c9be27ab99b55f212fd7eaf5a0c6 +Subproject commit 6e649def2bc4685cbfc3016af0bf215110f8e1e9 diff --git a/html/locale_en.json b/html/locale_en.json index 0807a2ab9..04e8c4bc0 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -130,7 +130,7 @@ {"id":"","label":"Set new defaults","localized":"","hint":"Set current values as default values for the user interface"}, {"id":"","label":"Benchmark","localized":"","hint":"Run benchmarks"}, {"id":"","label":"Models & Networks","localized":"","hint":"View lists of all available models and networks"}, - {"id":"","label":"Restore system defaults","localized":"","hint":"Restore default user interface values"} + {"id":"","label":"Restore defaults","localized":"","hint":"Restore default user interface values"} ], "txt2img tab": [ {"id":"","label":"Batch","localized":"","hint":"Additional batching options"}, diff --git a/html/locale_ko.json b/html/locale_ko.json index c36545816..bc64c3ad9 100644 --- a/html/locale_ko.json +++ b/html/locale_ko.json @@ -105,7 +105,7 @@ {"id":"","label":"User interface defaults","localized":"유저 인터페이스 기본값","hint":"Review and set current values as default values for the user interface"}, {"id":"","label":"View changes","localized":"변경 사항 확인","hint":"기본값과 현재 값 간의 변경 사항을 확인한다."}, {"id":"","label":"Set new defaults","localized":"새 기본값 설정","hint":"현재 UI 설정을 기본값으로 저장한다."}, - {"id":"","label":"Restore system defaults","localized":"시스템 기본값 복원","hint":"유저 인터페이스 기본값을 복원한다."} + {"id":"","label":"Restore defaults","localized":"시스템 기본값 복원","hint":"유저 인터페이스 기본값을 복원한다."} ], "txt2img tab": [ {"id":"","label":"Sampling method","localized":"샘플링 방법(샘플러)","hint":"이미지 생성 시 사용할 알고리즘을 지정한다."}, diff --git a/installer.py b/installer.py index 75e1f9607..97bb7fdda 100644 --- a/installer.py +++ b/installer.py @@ -272,19 +272,21 @@ def branch(folder): # update git repository -def update(folder, current_branch = False): +def update(folder, current_branch = False, rebase = True): try: git('config rebase.Autostash true') except Exception: pass + arg = '--rebase --force' if rebase else '' if current_branch: - git('pull --rebase --force', folder) - return + res = git(f'pull {arg}', folder) + return res b = branch(folder) if branch is None: - git('pull --rebase --force', folder) + res = git(f'pull {arg}', folder) else: - git(f'pull origin {b} --rebase --force', folder) + res = git(f'pull origin {b} {arg}', folder) + return res # clone git repository @@ -612,7 +614,7 @@ def list_extensions_folder(folder, quiet=False): # run installer for each installed and enabled extension and optionally update them -def install_extensions(): +def install_extensions(force=False): if args.profile: pr = cProfile.Profile() pr.enable() @@ -623,6 +625,7 @@ def install_extensions(): extensions_duplicates = [] extensions_enabled = [] extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir] + res = [] for folder in extension_folders: if not os.path.isdir(folder): continue @@ -633,10 +636,11 @@ def install_extensions(): extensions_duplicates.append(ext) continue extensions_enabled.append(ext) - if args.upgrade: + if args.upgrade or force: try: - update(os.path.join(folder, ext)) + res.append(update(os.path.join(folder, ext))) except Exception: + res.append(f'Error updating extension: {os.path.join(folder, ext)}') log.error(f'Error updating extension: {os.path.join(folder, ext)}') if not args.skip_extensions: run_extension_installer(os.path.join(folder, ext)) @@ -654,17 +658,18 @@ def install_extensions(): log.warning(f'Extensions duplicates: {extensions_duplicates}') if args.profile: print_profile(pr, 'Extensions') + return '\n'.join(res) # initialize and optionally update submodules -def install_submodules(): +def install_submodules(force=True): if args.profile: pr = cProfile.Profile() pr.enable() log.info('Verifying submodules') txt = git('submodule') # log.debug(f'Submodules list: {txt}') - if 'no submodule mapping found' in txt: + if force and 'no submodule mapping found' in txt: log.warning('Attempting repository recover') git('add .') git('stash') @@ -677,17 +682,19 @@ def install_submodules(): git('submodule --quiet update --init --recursive') git('submodule --quiet sync --recursive') submodules = txt.splitlines() + res = [] for submodule in submodules: try: name = submodule.split()[1].strip() if args.upgrade: - update(name) + res.append(update(name)) else: branch(name) except Exception: log.error(f'Error updating submodule: {submodule}') if args.profile: print_profile(pr, 'Submodule') + return '\n'.join(res) def ensure_base_requirements(): diff --git a/javascript/sdnext.css b/javascript/sdnext.css index 2ec0f35ad..c804b45ba 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -274,6 +274,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt /* main info */ .main-info { font-weight: var(--section-header-text-weight); color: var(--body-text-color-subdued); padding: 1em !important; margin-top: 2em !important; line-height: var(--line-lg) !important; } +.update-status { margin: 1em; line-height: 1.5em; } /* loader */ .splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; } diff --git a/modules/ui.py b/modules/ui.py index 1bd7e0c4e..8cd2eeeea 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -329,6 +329,10 @@ def create_ui(startup_timer = None): with gr.TabItem("Show all pages", elem_id="settings_show_all_pages"): create_dirty_indicator("show_all_pages", [], interactive=False) + with gr.TabItem("Update", id="system_update", elem_id="tab_update"): + from modules import update + update.create_ui() + with gr.TabItem("User interface", id="system_config", elem_id="tab_config"): loadsave.create_ui() create_dirty_indicator("tab_defaults", [], interactive=False) diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py index fbcf57523..69d79f879 100644 --- a/modules/ui_loadsave.py +++ b/modules/ui_loadsave.py @@ -250,7 +250,7 @@ class UiLoadsave: with gr.Row(elem_id="config_row"): self.ui_defaults_apply = gr.Button(value='Set new defaults', elem_id="ui_defaults_apply", variant="primary") self.ui_defaults_submenu = gr.Button(value='Set menu states', elem_id="ui_submenu_apply", variant="primary") - self.ui_defaults_restore = gr.Button(value='Restore system defaults', elem_id="ui_defaults_restore", variant="primary") + self.ui_defaults_restore = gr.Button(value='Restore defaults', elem_id="ui_defaults_restore", variant="primary") self.ui_defaults_view = gr.Button(value='Refresh changes', elem_id="ui_defaults_view", variant="secondary") self.ui_defaults_review = gr.HTML("", elem_id="ui_defaults_review") diff --git a/modules/update.py b/modules/update.py new file mode 100644 index 000000000..88c6ea9e1 --- /dev/null +++ b/modules/update.py @@ -0,0 +1,97 @@ +from types import SimpleNamespace +import gradio as gr +import installer as i + + +version = SimpleNamespace(**{ + 'url': '', + 'branch': '', + 'current': '0000-00-00', + 'chash': '0000000', + 'latest': '0000-00-00', + 'lhash': '0000000', +}) + + +def get_version(): + # try: + origin = i.git('remote get-url origin') + origin = origin.splitlines()[0] + version.branch = i.git('rev-parse --abbrev-ref HEAD') + version.branch = version.branch.splitlines()[0] + version.url = origin + '/tree/' + version.branch + + ver = i.git('log --pretty=format:"%h %ad" -1 --date=short') + ver = ver.splitlines()[0] + version.chash, version.current = ver.split(' ') + + ver = i.git(f'log origin/{version.branch} --pretty=format:"%h %ad" -1 --date=short') + ver = ver.splitlines()[0] + version.lhash, version.latest = ver.split(' ') + + # except Exception as e: + # i.log.error(f'Version check failed: {e}') + i.log.info(f'Version: {vars(version)}') + html = f''' +
URL: {version.url}
+
Current branch: {version.branch}
+
Current version: {version.current} hash {version.chash}
+
Latest version: {version.latest} hash {version.lhash}
+ ''' + return html + + +def apply_update(update_rebase, update_submodules, update_extensions): + html = [ + 'Updating...', + f'Core rebase: {update_rebase} | Submodules: {update_submodules} | Extensions: {update_extensions}', + f'
Current version: {version.current} hash {version.chash}
', + ] + get_version() + phash = version.chash + try: + if update_rebase: + i.git('add .') + i.git('stash') + res = i.update('.', current_branch=True, rebase=update_rebase) + html.append(res.replace('\n', '
')) + except Exception as e: + html.append(f'Error during repository upgrade: {e}') + i.log.error(f'Error during repository upgrade: {e}') + if update_submodules: + try: + res = i.install_submodules(force=True) + html.append(res.replace('\n', '
')) + except Exception as e: + html.append(f'Error during submodule upgrade: {e}') + i.log.error(f'Error during submodule upgrade: {e}') + if update_extensions: + try: + res = i.install_extensions(force=True) + html.append(res.replace('\n', '
')) + except Exception as e: + html.append(f'Error during extension upgrade: {e}') + i.log.error(f'Error during extension upgrade: {e}') + res = get_version() + html.append('') + html.append(res) + if phash != version.chash: + html.append('Update successful!
Perform full server restart to apply changes
') + else: + html.append('No changes') + return '
'.join(html) + +def create_ui(): + with gr.Row(): + update_check = gr.Button(value='Check for updates', elem_id="ui_update_check", variant="primary") + update_apply = gr.Button(value='Download updates', elem_id="ui_update_apply", variant="primary") + with gr.Row(): + update_rebase = gr.Checkbox(label='Rebase', elem_id="ui_update_rebase", value=True) + with gr.Row(): + update_submodules = gr.Checkbox(label='Submodules', elem_id="ui_update_submodules", value=True) + with gr.Row(): + update_extensions = gr.Checkbox(label='Extensions', elem_id="ui_update_extensions", value=True) + with gr.Row(): + update_status = gr.HTML("", elem_id="ui_update_status", elem_classes=['update-status']) + update_check.click(fn=get_version, inputs=[], outputs=[update_status]) + update_apply.click(fn=apply_update, inputs=[update_rebase, update_submodules, update_extensions], outputs=[update_status])