extensions.py 4.5 KB
Newer Older
1 2 3 4
import os
import sys
import traceback

5
import time
6
from datetime import datetime
7 8
import git

9
from modules import shared
10
from modules.paths_internal import extensions_dir, extensions_builtin_dir, script_path
11 12 13

extensions = []

14 15 16
if not os.path.exists(extensions_dir):
    os.makedirs(extensions_dir)

17 18

def active():
19 20 21 22 23 24
    if shared.opts.disable_all_extensions == "all":
        return []
    elif shared.opts.disable_all_extensions == "extra":
        return [x for x in extensions if x.enabled and x.is_builtin]
    else:
        return [x for x in extensions if x.enabled]
25 26 27


class Extension:
A
AUTOMATIC 已提交
28
    def __init__(self, name, path, enabled=True, is_builtin=False):
29 30 31 32 33
        self.name = name
        self.path = path
        self.enabled = enabled
        self.status = ''
        self.can_update = False
A
AUTOMATIC 已提交
34
        self.is_builtin = is_builtin
35 36
        self.commit_hash = ''
        self.commit_date = None
37
        self.version = ''
38
        self.branch = None
39 40 41 42
        self.remote = None
        self.have_info_from_repo = False

    def read_info_from_repo(self):
43
        if self.is_builtin or self.have_info_from_repo:
44 45 46
            return

        self.have_info_from_repo = True
47 48 49

        repo = None
        try:
50 51
            if os.path.exists(os.path.join(self.path, ".git")):
                repo = git.Repo(self.path)
52
        except Exception:
53
            print(f"Error reading github repository info from {self.path}:", file=sys.stderr)
54 55 56 57 58
            print(traceback.format_exc(), file=sys.stderr)

        if repo is None or repo.bare:
            self.remote = None
        else:
59 60
            try:
                self.status = 'unknown'
61
                self.remote = next(repo.remote().urls, None)
62
                head = repo.head.commit
63 64 65 66 67 68 69 70 71
                self.commit_date = repo.head.commit.committed_date
                ts = time.asctime(time.gmtime(self.commit_date))
                if repo.active_branch:
                    self.branch = repo.active_branch.name
                self.commit_hash = head.hexsha
                self.version = f'{self.commit_hash[:8]} ({ts})'

            except Exception as ex:
                print(f"Failed reading extension data from Git repository ({self.name}): {ex}", file=sys.stderr)
72
                self.remote = None
73 74 75 76 77 78 79 80 81 82

    def list_files(self, subdir, extension):
        from modules import scripts

        dirpath = os.path.join(self.path, subdir)
        if not os.path.isdir(dirpath):
            return []

        res = []
        for filename in sorted(os.listdir(dirpath)):
83
            res.append(scripts.ScriptFile(self.path, filename, os.path.join(dirpath, filename)))
84 85 86 87 88 89 90

        res = [x for x in res if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]

        return res

    def check_updates(self):
        repo = git.Repo(self.path)
A
Adam Huganir 已提交
91
        for fetch in repo.remote().fetch(dry_run=True):
92 93 94 95 96 97 98 99
            if fetch.flags != fetch.HEAD_UPTODATE:
                self.can_update = True
                self.status = "behind"
                return

        self.can_update = False
        self.status = "latest"

100
    def fetch_and_reset_hard(self, commit='origin'):
101
        repo = git.Repo(self.path)
102 103
        # Fix: `error: Your local changes to the following files would be overwritten by merge`,
        # because WSL2 Docker set 755 file permissions instead of 644, this results to the error.
A
Adam Huganir 已提交
104
        repo.git.fetch(all=True)
105
        repo.git.reset(commit, hard=True)
106 107 108 109 110


def list_extensions():
    extensions.clear()

111
    if not os.path.isdir(extensions_dir):
112 113
        return

114
    if shared.opts.disable_all_extensions == "all":
115
        print("*** \"Disable all extensions\" option was set, will not load any extensions ***")
116 117
    elif shared.opts.disable_all_extensions == "extra":
        print("*** \"Disable all extensions\" option was set, will only load built-in extensions ***")
118

119
    extension_paths = []
120
    for dirname in [extensions_dir, extensions_builtin_dir]:
A
AUTOMATIC 已提交
121 122
        if not os.path.isdir(dirname):
            return
123

A
AUTOMATIC 已提交
124 125 126 127 128
        for extension_dirname in sorted(os.listdir(dirname)):
            path = os.path.join(dirname, extension_dirname)
            if not os.path.isdir(path):
                continue

129
            extension_paths.append((extension_dirname, path, dirname == extensions_builtin_dir))
A
AUTOMATIC 已提交
130

131
    for dirname, path, is_builtin in extension_paths:
A
AUTOMATIC 已提交
132
        extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions, is_builtin=is_builtin)
133
        extensions.append(extension)