ominfra 0.0.0.dev138__py3-none-any.whl → 0.0.0.dev140__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. ominfra/manage/__init__.py +13 -0
  2. ominfra/manage/{new/commands → commands}/base.py +9 -7
  3. ominfra/manage/{new/commands → commands}/subprocess.py +20 -15
  4. ominfra/manage/main.py +175 -0
  5. ominfra/manage/payload.py +35 -0
  6. ominfra/manage/spawning.py +100 -0
  7. ominfra/pyremote.py +18 -8
  8. ominfra/scripts/journald2aws.py +7 -0
  9. ominfra/{manage/new/_manage.py → scripts/manage.py} +248 -153
  10. ominfra/scripts/supervisor.py +7 -0
  11. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/METADATA +3 -3
  12. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/RECORD +17 -44
  13. ominfra/manage/deploy/_executor.py +0 -1415
  14. ominfra/manage/deploy/configs.py +0 -19
  15. ominfra/manage/deploy/executor/__init__.py +0 -1
  16. ominfra/manage/deploy/executor/base.py +0 -115
  17. ominfra/manage/deploy/executor/concerns/__init__.py +0 -0
  18. ominfra/manage/deploy/executor/concerns/dirs.py +0 -28
  19. ominfra/manage/deploy/executor/concerns/nginx.py +0 -47
  20. ominfra/manage/deploy/executor/concerns/repo.py +0 -17
  21. ominfra/manage/deploy/executor/concerns/supervisor.py +0 -46
  22. ominfra/manage/deploy/executor/concerns/systemd.py +0 -88
  23. ominfra/manage/deploy/executor/concerns/user.py +0 -25
  24. ominfra/manage/deploy/executor/concerns/venv.py +0 -22
  25. ominfra/manage/deploy/executor/main.py +0 -119
  26. ominfra/manage/deploy/poly/__init__.py +0 -1
  27. ominfra/manage/deploy/poly/_main.py +0 -975
  28. ominfra/manage/deploy/poly/base.py +0 -178
  29. ominfra/manage/deploy/poly/configs.py +0 -38
  30. ominfra/manage/deploy/poly/deploy.py +0 -25
  31. ominfra/manage/deploy/poly/main.py +0 -18
  32. ominfra/manage/deploy/poly/nginx.py +0 -60
  33. ominfra/manage/deploy/poly/repo.py +0 -41
  34. ominfra/manage/deploy/poly/runtime.py +0 -39
  35. ominfra/manage/deploy/poly/site.py +0 -11
  36. ominfra/manage/deploy/poly/supervisor.py +0 -64
  37. ominfra/manage/deploy/poly/venv.py +0 -52
  38. ominfra/manage/deploy/remote.py +0 -91
  39. ominfra/manage/manage.py +0 -12
  40. ominfra/manage/new/__init__.py +0 -1
  41. ominfra/manage/new/commands/__init__.py +0 -0
  42. ominfra/manage/new/main.py +0 -234
  43. /ominfra/manage/{deploy → commands}/__init__.py +0 -0
  44. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/LICENSE +0 -0
  45. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/WHEEL +0 -0
  46. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/entry_points.txt +0 -0
  47. {ominfra-0.0.0.dev138.dist-info → ominfra-0.0.0.dev140.dist-info}/top_level.txt +0 -0
@@ -1,178 +0,0 @@
1
- # ruff: noqa: UP006 UP007
2
- import abc
3
- import dataclasses as dc
4
- import typing as ta
5
-
6
- from .configs import DeployConcernConfig # noqa
7
- from .configs import DeployConfig
8
- from .configs import SiteConcernConfig # noqa
9
- from .configs import SiteConfig
10
-
11
-
12
- T = ta.TypeVar('T')
13
-
14
- ConcernT = ta.TypeVar('ConcernT')
15
- ConfigT = ta.TypeVar('ConfigT')
16
-
17
- SiteConcernT = ta.TypeVar('SiteConcernT', bound='SiteConcern')
18
- SiteConcernConfigT = ta.TypeVar('SiteConcernConfigT', bound='SiteConcernConfig')
19
-
20
- DeployConcernT = ta.TypeVar('DeployConcernT', bound='DeployConcern')
21
- DeployConcernConfigT = ta.TypeVar('DeployConcernConfigT', bound='DeployConcernConfig')
22
-
23
-
24
- ##
25
-
26
-
27
- @dc.dataclass(frozen=True)
28
- class FsItem(abc.ABC):
29
- path: str
30
-
31
- @property
32
- @abc.abstractmethod
33
- def is_dir(self) -> bool:
34
- raise NotImplementedError
35
-
36
-
37
- @dc.dataclass(frozen=True)
38
- class FsFile(FsItem):
39
- @property
40
- def is_dir(self) -> bool:
41
- return False
42
-
43
-
44
- @dc.dataclass(frozen=True)
45
- class FsDir(FsItem):
46
- @property
47
- def is_dir(self) -> bool:
48
- return True
49
-
50
-
51
- ##
52
-
53
-
54
- class Runtime(abc.ABC):
55
- class Stat(ta.NamedTuple):
56
- path: str
57
- is_dir: bool
58
-
59
- @abc.abstractmethod
60
- def stat(self, p: str) -> ta.Optional[Stat]:
61
- raise NotImplementedError
62
-
63
- @abc.abstractmethod
64
- def make_dirs(self, p: str, exist_ok: bool = False) -> None:
65
- raise NotImplementedError
66
-
67
- @abc.abstractmethod
68
- def write_file(self, p: str, c: ta.Union[str, bytes]) -> None:
69
- raise NotImplementedError
70
-
71
- @abc.abstractmethod
72
- def sh(self, *ss: str) -> None:
73
- raise NotImplementedError
74
-
75
-
76
- ##
77
-
78
-
79
- class ConcernsContainer(abc.ABC, ta.Generic[ConcernT, ConfigT]):
80
- concern_cls: ta.ClassVar[type]
81
-
82
- def __init__(
83
- self,
84
- config: ConfigT,
85
- ) -> None:
86
- super().__init__()
87
- self._config = config
88
-
89
- concern_cls_dct = self._concern_cls_by_config_cls()
90
- self._concerns = [
91
- concern_cls_dct[type(c)](c, self) # type: ignore
92
- for c in config.concerns # type: ignore
93
- ]
94
- self._concerns_by_cls: ta.Dict[ta.Type[ConcernT], ConcernT] = {}
95
- for c in self._concerns:
96
- if type(c) in self._concerns_by_cls:
97
- raise TypeError(f'Duplicate concern type: {c}')
98
- self._concerns_by_cls[type(c)] = c
99
-
100
- @classmethod
101
- def _concern_cls_by_config_cls(cls) -> ta.Mapping[type, ta.Type[ConcernT]]:
102
- return { # noqa
103
- c.Config: c # type: ignore
104
- for c in cls.concern_cls.__subclasses__()
105
- }
106
-
107
- @property
108
- def config(self) -> ConfigT:
109
- return self._config
110
-
111
- @property
112
- def concerns(self) -> ta.List[ConcernT]:
113
- return self._concerns
114
-
115
- def concern(self, cls: ta.Type[T]) -> T:
116
- return self._concerns_by_cls[cls] # type: ignore
117
-
118
-
119
- ##
120
-
121
-
122
- class SiteConcern(abc.ABC, ta.Generic[SiteConcernConfigT]):
123
- def __init__(self, config: SiteConcernConfigT, site: 'Site') -> None:
124
- super().__init__()
125
- self._config = config
126
- self._site = site
127
-
128
- @property
129
- def config(self) -> SiteConcernConfigT:
130
- return self._config
131
-
132
- @abc.abstractmethod
133
- def run(self, runtime: Runtime) -> None:
134
- raise NotImplementedError
135
-
136
-
137
- ##
138
-
139
-
140
- class Site(ConcernsContainer[SiteConcern, SiteConfig]):
141
- @abc.abstractmethod
142
- def run(self, runtime: Runtime) -> None:
143
- raise NotImplementedError
144
-
145
-
146
- ##
147
-
148
-
149
- class DeployConcern(abc.ABC, ta.Generic[DeployConcernConfigT]):
150
- def __init__(self, config: DeployConcernConfigT, deploy: 'Deploy') -> None:
151
- super().__init__()
152
- self._config = config
153
- self._deploy = deploy
154
-
155
- @property
156
- def config(self) -> DeployConcernConfigT:
157
- return self._config
158
-
159
- def fs_items(self) -> ta.Sequence[FsItem]:
160
- return []
161
-
162
- @abc.abstractmethod
163
- def run(self, runtime: Runtime) -> None:
164
- raise NotImplementedError
165
-
166
-
167
- ##
168
-
169
-
170
- class Deploy(ConcernsContainer[DeployConcern, DeployConfig]):
171
- @property
172
- @abc.abstractmethod
173
- def site(self) -> Site:
174
- raise NotImplementedError
175
-
176
- @abc.abstractmethod
177
- def run(self, runtime: Runtime) -> None:
178
- raise NotImplementedError
@@ -1,38 +0,0 @@
1
- # ruff: noqa: UP006
2
- import abc
3
- import dataclasses as dc
4
- import typing as ta
5
-
6
-
7
- ##
8
-
9
-
10
- @dc.dataclass(frozen=True)
11
- class SiteConcernConfig(abc.ABC): # noqa
12
- pass
13
-
14
-
15
- @dc.dataclass(frozen=True)
16
- class SiteConfig:
17
- user = 'omlish'
18
-
19
- root_dir: str = '~/deploy'
20
-
21
- concerns: ta.List[SiteConcernConfig] = dc.field(default_factory=list)
22
-
23
-
24
- ##
25
-
26
-
27
- @dc.dataclass(frozen=True)
28
- class DeployConcernConfig(abc.ABC): # noqa
29
- pass
30
-
31
-
32
- @dc.dataclass(frozen=True)
33
- class DeployConfig:
34
- site: SiteConfig
35
-
36
- name: str
37
-
38
- concerns: ta.List[DeployConcernConfig] = dc.field(default_factory=list)
@@ -1,25 +0,0 @@
1
- from .base import Deploy
2
- from .base import DeployConcern
3
- from .base import Runtime
4
- from .base import Site
5
- from .configs import DeployConfig
6
-
7
-
8
- class DeployImpl(Deploy):
9
- concern_cls = DeployConcern
10
-
11
- def __init__(
12
- self,
13
- config: DeployConfig,
14
- site: Site,
15
- ) -> None:
16
- super().__init__(config)
17
- self._site = site
18
-
19
- @property
20
- def site(self) -> Site:
21
- return self._site
22
-
23
- def run(self, runtime: Runtime) -> None:
24
- for c in self._concerns:
25
- c.run(runtime)
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env python3
2
- # @omlish-amalg ./_main.py
3
- from .deploy import DeployImpl # noqa
4
- from .nginx import NginxDeployConcern # noqa
5
- from .nginx import NginxSiteConcern # noqa
6
- from .repo import RepoDeployConcern # noqa
7
- from .runtime import RuntimeImpl # noqa
8
- from .site import SiteImpl # noqa
9
- from .supervisor import SupervisorDeployConcern # noqa
10
- from .venv import VenvDeployConcern # noqa
11
-
12
-
13
- def _main() -> None:
14
- pass
15
-
16
-
17
- if __name__ == '__main__':
18
- _main()
@@ -1,60 +0,0 @@
1
- import dataclasses as dc
2
- import os.path
3
- import textwrap
4
- import typing as ta
5
-
6
- from omlish.lite.cached import cached_nullary
7
-
8
- from .base import DeployConcern
9
- from .base import FsFile
10
- from .base import FsItem
11
- from .base import Runtime
12
- from .base import SiteConcern
13
- from .configs import DeployConcernConfig
14
- from .configs import SiteConcernConfig
15
-
16
-
17
- class NginxSiteConcern(SiteConcern['NginxSiteConcern.Config']):
18
- @dc.dataclass(frozen=True)
19
- class Config(SiteConcernConfig):
20
- global_conf_file: str = '/etc/nginx/sites-enabled/omlish.conf'
21
-
22
- @cached_nullary
23
- def confs_dir(self) -> str:
24
- return os.path.join(self._site.config.root_dir, 'conf', 'nginx')
25
-
26
- def run(self, runtime: Runtime) -> None:
27
- if runtime.stat(self._config.global_conf_file) is None:
28
- runtime.write_file(
29
- self._config.global_conf_file,
30
- f'include {self.confs_dir()}/*.conf;\n',
31
- )
32
-
33
-
34
- class NginxDeployConcern(DeployConcern['NginxDeployConcern.Config']):
35
- @dc.dataclass(frozen=True)
36
- class Config(DeployConcernConfig):
37
- listen_port: int = 80
38
- proxy_port: int = 8000
39
-
40
- @cached_nullary
41
- def conf_file(self) -> str:
42
- return os.path.join(self._deploy.site.concern(NginxSiteConcern).confs_dir(), self._deploy.config.name + '.conf')
43
-
44
- @cached_nullary
45
- def fs_items(self) -> ta.Sequence[FsItem]:
46
- return [FsFile(self.conf_file())]
47
-
48
- def run(self, runtime: Runtime) -> None:
49
- runtime.make_dirs(os.path.dirname(self.conf_file()))
50
-
51
- conf = textwrap.dedent(f"""
52
- server {{
53
- listen {self._config.listen_port};
54
- location / {{
55
- proxy_pass http://127.0.0.1:{self._config.proxy_port}/;
56
- }}
57
- }}
58
- """)
59
-
60
- runtime.write_file(self.conf_file(), conf)
@@ -1,41 +0,0 @@
1
- import dataclasses as dc
2
- import os.path
3
- import typing as ta
4
-
5
- from omlish.lite.cached import cached_nullary
6
-
7
- from .base import DeployConcern
8
- from .base import FsDir
9
- from .base import FsItem
10
- from .base import Runtime
11
- from .configs import DeployConcernConfig
12
-
13
-
14
- class RepoDeployConcern(DeployConcern['RepoDeployConcern.Config']):
15
- @dc.dataclass(frozen=True)
16
- class Config(DeployConcernConfig):
17
- url: str
18
- revision: str = 'master'
19
- init_submodules: bool = False
20
-
21
- @cached_nullary
22
- def repo_dir(self) -> str:
23
- return os.path.join(self._deploy.site.config.root_dir, 'repos', self._deploy.config.name)
24
-
25
- @cached_nullary
26
- def fs_items(self) -> ta.Sequence[FsItem]:
27
- return [FsDir(self.repo_dir())]
28
-
29
- def run(self, runtime: Runtime) -> None:
30
- runtime.make_dirs(self.repo_dir())
31
-
32
- runtime.sh(
33
- f'cd {self.repo_dir()}',
34
- 'git init',
35
- f'git remote add origin {self._config.url}',
36
- f'git fetch --depth 1 origin {self._config.revision}',
37
- 'git checkout FETCH_HEAD',
38
- *([
39
- 'git submodule update --init',
40
- ] if self._config.init_submodules else []),
41
- )
@@ -1,39 +0,0 @@
1
- # ruff: noqa: UP007
2
- import os.path
3
- import stat
4
- import typing as ta
5
-
6
- from omlish.lite.logs import log
7
- from omlish.lite.subprocesses import subprocess_check_call
8
-
9
- from .base import Runtime
10
-
11
-
12
- class RuntimeImpl(Runtime):
13
- def __init__(self) -> None:
14
- super().__init__()
15
-
16
- def stat(self, p: str) -> ta.Optional[Runtime.Stat]:
17
- try:
18
- st = os.stat(p)
19
- except FileNotFoundError:
20
- return None
21
- else:
22
- return Runtime.Stat(
23
- path=p,
24
- is_dir=bool(st.st_mode & stat.S_IFDIR),
25
- )
26
-
27
- def make_dirs(self, p: str, exist_ok: bool = False) -> None:
28
- os.makedirs(p, exist_ok=exist_ok)
29
-
30
- def write_file(self, p: str, c: ta.Union[str, bytes]) -> None:
31
- if os.path.exists(p):
32
- raise RuntimeError(f'Path exists: {p}')
33
- with open(p, 'w' if isinstance(c, str) else 'wb') as f:
34
- f.write(c)
35
-
36
- def sh(self, *ss: str) -> None:
37
- s = ' && '.join(ss)
38
- log.info('Executing: %s', s)
39
- subprocess_check_call(s, shell=True)
@@ -1,11 +0,0 @@
1
- from .base import Runtime
2
- from .base import Site
3
- from .base import SiteConcern
4
-
5
-
6
- class SiteImpl(Site):
7
- concern_cls = SiteConcern
8
-
9
- def run(self, runtime: Runtime) -> None:
10
- for c in self._concerns:
11
- c.run(runtime)
@@ -1,64 +0,0 @@
1
- import dataclasses as dc
2
- import os.path
3
- import textwrap
4
- import typing as ta
5
-
6
- from omlish.lite.cached import cached_nullary
7
-
8
- from .base import DeployConcern
9
- from .base import FsFile
10
- from .base import FsItem
11
- from .base import Runtime
12
- from .configs import DeployConcernConfig
13
- from .repo import RepoDeployConcern
14
- from .venv import VenvDeployConcern
15
-
16
-
17
- # class SupervisorSiteConcern(SiteConcern['SupervisorSiteConcern.Config']):
18
- # @dc.dataclass(frozen=True)
19
- # class Config(DeployConcern.Config):
20
- # global_conf_file: str = '/etc/supervisor/conf.d/supervisord.conf'
21
- #
22
- # def run(self) -> None:
23
- # sup_conf_dir = os.path.join(self._d.home_dir(), 'conf/supervisor')
24
- # with open(self._d.host_cfg.global_supervisor_conf_file_path) as f:
25
- # glo_sup_conf = f.read()
26
- # if sup_conf_dir not in glo_sup_conf:
27
- # log.info('Updating global supervisor conf at %s', self._d.host_cfg.global_supervisor_conf_file_path) # noqa
28
- # glo_sup_conf += textwrap.dedent(f"""
29
- # [include]
30
- # files = {self._d.home_dir()}/conf/supervisor/*.conf
31
- # """)
32
- # with open(self._d.host_cfg.global_supervisor_conf_file_path, 'w') as f:
33
- # f.write(glo_sup_conf)
34
-
35
-
36
- class SupervisorDeployConcern(DeployConcern['SupervisorDeployConcern.Config']):
37
- @dc.dataclass(frozen=True)
38
- class Config(DeployConcernConfig):
39
- entrypoint: str
40
-
41
- @cached_nullary
42
- def conf_file(self) -> str:
43
- return os.path.join(self._deploy.site.config.root_dir, 'conf', 'supervisor', self._deploy.config.name + '.conf')
44
-
45
- @cached_nullary
46
- def fs_items(self) -> ta.Sequence[FsItem]:
47
- return [FsFile(self.conf_file())]
48
-
49
- def run(self, runtime: Runtime) -> None:
50
- runtime.make_dirs(os.path.dirname(self.conf_file()))
51
-
52
- rd = self._deploy.concern(RepoDeployConcern).repo_dir()
53
- vx = self._deploy.concern(VenvDeployConcern).exe()
54
-
55
- conf = textwrap.dedent(f"""
56
- [program:{self._deploy.config.name}]
57
- command={vx} -m {self._config.entrypoint}
58
- directory={rd}
59
- user={self._deploy.site.config.user}
60
- autostart=true
61
- autorestart=true
62
- """)
63
-
64
- runtime.write_file(self.conf_file(), conf)
@@ -1,52 +0,0 @@
1
- import dataclasses as dc
2
- import os.path
3
- import typing as ta
4
-
5
- from omlish.lite.cached import cached_nullary
6
-
7
- from .base import DeployConcern
8
- from .base import FsDir
9
- from .base import FsItem
10
- from .base import Runtime
11
- from .configs import DeployConcernConfig
12
- from .repo import RepoDeployConcern
13
-
14
-
15
- class VenvDeployConcern(DeployConcern['VenvDeployConcern.Config']):
16
- @dc.dataclass(frozen=True)
17
- class Config(DeployConcernConfig):
18
- interp_version: str
19
- requirements_txt: str = 'requirements.txt'
20
-
21
- @cached_nullary
22
- def venv_dir(self) -> str:
23
- return os.path.join(self._deploy.site.config.root_dir, 'venvs', self._deploy.config.name)
24
-
25
- @cached_nullary
26
- def fs_items(self) -> ta.Sequence[FsItem]:
27
- return [FsDir(self.venv_dir())]
28
-
29
- @cached_nullary
30
- def exe(self) -> str:
31
- return os.path.join(self.venv_dir(), 'bin', 'python')
32
-
33
- def run(self, runtime: Runtime) -> None:
34
- runtime.make_dirs(self.venv_dir())
35
-
36
- rd = self._deploy.concern(RepoDeployConcern).repo_dir()
37
-
38
- l, r = os.path.split(self.venv_dir())
39
-
40
- # FIXME: lol
41
- py_exe = 'python3'
42
-
43
- runtime.sh(
44
- f'cd {l}',
45
- f'{py_exe} -mvenv {r}',
46
-
47
- # https://stackoverflow.com/questions/77364550/attributeerror-module-pkgutil-has-no-attribute-impimporter-did-you-mean
48
- f'{self.exe()} -m ensurepip',
49
- f'{self.exe()} -mpip install --upgrade setuptools pip',
50
-
51
- f'{self.exe()} -mpip install -r {rd}/{self._config.requirements_txt}', # noqa
52
- )
@@ -1,91 +0,0 @@
1
- """
2
- See:
3
- - piku, obviously
4
- - https://github.com/mitogen-hq/mitogen/
5
-
6
- git init
7
- git remote add local ~/src/wrmsr/omlish/.git
8
- git fetch --depth=1 local master
9
- git remote add origin https://github.com/wrmsr/omlish
10
- git fetch --depth=1 origin master
11
- git checkout origin/master
12
-
13
- {base_path}/{deploys}/
14
- current ->
15
- previous ->
16
- 20240522T120000_{rev}
17
- """
18
- import asyncio
19
- import itertools
20
- import os.path
21
- import shlex
22
- import tempfile
23
-
24
- from omlish import check
25
-
26
- from ... import cmds
27
-
28
-
29
- def render_script(*cs: list[str] | tuple[str, ...]) -> str:
30
- return ' '.join(itertools.chain.from_iterable(
31
- [
32
- *(['&&'] if i > 0 else []),
33
- shlex.join(check.not_isinstance(l, str)),
34
- ]
35
- for i, l in enumerate(cs)
36
- ))
37
-
38
-
39
- async def do_remote_deploy(
40
- cr: cmds.CommandRunner,
41
- rev: str = 'master',
42
- *,
43
- local_repo_path: str | None = None,
44
- skip_submodules: bool = False,
45
- ) -> None:
46
- clone_script = [
47
- ['git', 'init'],
48
-
49
- *([
50
- ['git', 'remote', 'add', 'local', local_repo_path],
51
- ['git', 'fetch', '--depth=1', 'local', rev],
52
- ] if local_repo_path is not None else ()),
53
-
54
- ['git', 'remote', 'add', 'origin', 'https://github.com/wrmsr/omlish'],
55
- ['git', 'fetch', '--depth=1', 'origin', rev],
56
- ['git', 'checkout', f'origin/{rev}'],
57
-
58
- *([['git', 'submodule', 'update', '--init']] if not skip_submodules else ()),
59
-
60
- ['make', 'venv-deploy'],
61
- ]
62
-
63
- res = await cr.run_command(cr.Command([
64
- 'sh', '-c', render_script(
65
- ['mkdir', 'omlish'],
66
- ['cd', 'omlish'],
67
- *clone_script,
68
- ),
69
- ]))
70
- res.check()
71
-
72
-
73
- async def _a_main():
74
- cwd = tempfile.mkdtemp()
75
- print(cwd)
76
-
77
- bootstrap_git_path = os.path.join(os.getcwd(), '.git')
78
- check.state(os.path.isdir(bootstrap_git_path))
79
-
80
- cr: cmds.CommandRunner = cmds.LocalCommandRunner(cmds.LocalCommandRunner.Config(
81
- cwd=cwd,
82
- ))
83
-
84
- await do_remote_deploy(
85
- cr,
86
- local_repo_path=os.path.expanduser('~/src/wrmsr/omlish/.git'),
87
- )
88
-
89
-
90
- if __name__ == '__main__':
91
- asyncio.run(_a_main())
ominfra/manage/manage.py DELETED
@@ -1,12 +0,0 @@
1
- """
2
- Jobs:
3
- - globals
4
- - pkgs
5
- - pyenv
6
- - tailscale
7
- - docker
8
- - system nginx
9
- - system service manager - systemd / supervisor
10
- - users
11
- - firewall
12
- """
@@ -1 +0,0 @@
1
- # @omlish-lite
File without changes