ruyi 0.39.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ruyi/__init__.py +21 -0
- ruyi/__main__.py +98 -0
- ruyi/cli/__init__.py +5 -0
- ruyi/cli/builtin_commands.py +14 -0
- ruyi/cli/cmd.py +224 -0
- ruyi/cli/completer.py +50 -0
- ruyi/cli/completion.py +26 -0
- ruyi/cli/config_cli.py +153 -0
- ruyi/cli/main.py +111 -0
- ruyi/cli/self_cli.py +295 -0
- ruyi/cli/user_input.py +127 -0
- ruyi/cli/version_cli.py +45 -0
- ruyi/config/__init__.py +401 -0
- ruyi/config/editor.py +92 -0
- ruyi/config/errors.py +76 -0
- ruyi/config/news.py +39 -0
- ruyi/config/schema.py +197 -0
- ruyi/device/__init__.py +0 -0
- ruyi/device/provision.py +591 -0
- ruyi/device/provision_cli.py +40 -0
- ruyi/log/__init__.py +272 -0
- ruyi/mux/.gitignore +1 -0
- ruyi/mux/__init__.py +0 -0
- ruyi/mux/runtime.py +213 -0
- ruyi/mux/venv/__init__.py +12 -0
- ruyi/mux/venv/emulator_cfg.py +41 -0
- ruyi/mux/venv/maker.py +782 -0
- ruyi/mux/venv/venv_cli.py +92 -0
- ruyi/mux/venv_cfg.py +214 -0
- ruyi/pluginhost/__init__.py +0 -0
- ruyi/pluginhost/api.py +206 -0
- ruyi/pluginhost/ctx.py +222 -0
- ruyi/pluginhost/paths.py +135 -0
- ruyi/pluginhost/plugin_cli.py +37 -0
- ruyi/pluginhost/unsandboxed.py +246 -0
- ruyi/py.typed +0 -0
- ruyi/resource_bundle/__init__.py +20 -0
- ruyi/resource_bundle/__main__.py +55 -0
- ruyi/resource_bundle/data.py +26 -0
- ruyi/ruyipkg/__init__.py +0 -0
- ruyi/ruyipkg/admin_checksum.py +88 -0
- ruyi/ruyipkg/admin_cli.py +83 -0
- ruyi/ruyipkg/atom.py +184 -0
- ruyi/ruyipkg/augmented_pkg.py +212 -0
- ruyi/ruyipkg/canonical_dump.py +320 -0
- ruyi/ruyipkg/checksum.py +39 -0
- ruyi/ruyipkg/cli_completion.py +42 -0
- ruyi/ruyipkg/distfile.py +208 -0
- ruyi/ruyipkg/entity.py +387 -0
- ruyi/ruyipkg/entity_cli.py +123 -0
- ruyi/ruyipkg/entity_provider.py +273 -0
- ruyi/ruyipkg/fetch.py +271 -0
- ruyi/ruyipkg/host.py +55 -0
- ruyi/ruyipkg/install.py +554 -0
- ruyi/ruyipkg/install_cli.py +150 -0
- ruyi/ruyipkg/list.py +126 -0
- ruyi/ruyipkg/list_cli.py +79 -0
- ruyi/ruyipkg/list_filter.py +173 -0
- ruyi/ruyipkg/msg.py +99 -0
- ruyi/ruyipkg/news.py +123 -0
- ruyi/ruyipkg/news_cli.py +78 -0
- ruyi/ruyipkg/news_store.py +183 -0
- ruyi/ruyipkg/pkg_manifest.py +657 -0
- ruyi/ruyipkg/profile.py +208 -0
- ruyi/ruyipkg/profile_cli.py +33 -0
- ruyi/ruyipkg/protocols.py +55 -0
- ruyi/ruyipkg/repo.py +763 -0
- ruyi/ruyipkg/state.py +345 -0
- ruyi/ruyipkg/unpack.py +369 -0
- ruyi/ruyipkg/unpack_method.py +91 -0
- ruyi/ruyipkg/update_cli.py +54 -0
- ruyi/telemetry/__init__.py +0 -0
- ruyi/telemetry/aggregate.py +72 -0
- ruyi/telemetry/event.py +41 -0
- ruyi/telemetry/node_info.py +192 -0
- ruyi/telemetry/provider.py +411 -0
- ruyi/telemetry/scope.py +43 -0
- ruyi/telemetry/store.py +238 -0
- ruyi/telemetry/telemetry_cli.py +127 -0
- ruyi/utils/__init__.py +0 -0
- ruyi/utils/ar.py +74 -0
- ruyi/utils/ci.py +63 -0
- ruyi/utils/frontmatter.py +38 -0
- ruyi/utils/git.py +169 -0
- ruyi/utils/global_mode.py +204 -0
- ruyi/utils/l10n.py +83 -0
- ruyi/utils/markdown.py +73 -0
- ruyi/utils/nuitka.py +33 -0
- ruyi/utils/porcelain.py +51 -0
- ruyi/utils/prereqs.py +77 -0
- ruyi/utils/ssl_patch.py +170 -0
- ruyi/utils/templating.py +34 -0
- ruyi/utils/toml.py +115 -0
- ruyi/utils/url.py +7 -0
- ruyi/utils/xdg_basedir.py +80 -0
- ruyi/version.py +67 -0
- ruyi-0.39.0.dist-info/LICENSE-Apache.txt +201 -0
- ruyi-0.39.0.dist-info/METADATA +403 -0
- ruyi-0.39.0.dist-info/RECORD +101 -0
- ruyi-0.39.0.dist-info/WHEEL +4 -0
- ruyi-0.39.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import re
|
|
3
|
+
from typing import Any, Final, TypedDict
|
|
4
|
+
|
|
5
|
+
from ..config.news import NewsReadStatusStore
|
|
6
|
+
from ..utils import frontmatter
|
|
7
|
+
from ..utils.porcelain import PorcelainEntity, PorcelainEntityType
|
|
8
|
+
from ..utils.l10n import match_lang_code
|
|
9
|
+
|
|
10
|
+
NEWS_FILENAME_RE: Final = re.compile(r"^(\d+-\d{2}-\d{2}-.*?)(\.[0-9A-Za-z_-]+)?\.md$")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@functools.total_ordering
|
|
14
|
+
class NewsItemNameMetadata:
|
|
15
|
+
def __init__(self, id: str, lang: str) -> None:
|
|
16
|
+
self.id = id
|
|
17
|
+
self.lang = lang
|
|
18
|
+
|
|
19
|
+
def __eq__(self, other: Any) -> bool:
|
|
20
|
+
if not isinstance(other, NewsItemNameMetadata):
|
|
21
|
+
return NotImplemented
|
|
22
|
+
return self.id == other.id
|
|
23
|
+
|
|
24
|
+
def __lt__(self, other: Any) -> bool:
|
|
25
|
+
if not isinstance(other, NewsItemNameMetadata):
|
|
26
|
+
return NotImplemented
|
|
27
|
+
|
|
28
|
+
# order by id in lexical order
|
|
29
|
+
return self.id < other.id
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def parse_news_filename(filename: str) -> NewsItemNameMetadata | None:
|
|
33
|
+
m = NEWS_FILENAME_RE.match(filename)
|
|
34
|
+
if m is None:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
id = m.group(1)
|
|
38
|
+
lang = m.group(2)
|
|
39
|
+
if not lang:
|
|
40
|
+
lang = "zh_CN" # TODO: kill after l10n work is complete
|
|
41
|
+
else:
|
|
42
|
+
lang = lang[1:] # strip the dot prefix
|
|
43
|
+
|
|
44
|
+
return NewsItemNameMetadata(id, lang)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class NewsItemStore:
|
|
48
|
+
def __init__(self, rs_store: NewsReadStatusStore) -> None:
|
|
49
|
+
self._buf_news_by_ids: dict[str, NewsItem] = {}
|
|
50
|
+
self._newsitems: list[NewsItem]
|
|
51
|
+
self._rs_store = rs_store
|
|
52
|
+
|
|
53
|
+
def add(self, filename: str, contents: str) -> None:
|
|
54
|
+
md = parse_news_filename(filename)
|
|
55
|
+
if md is None:
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
post = frontmatter.loads(contents)
|
|
59
|
+
|
|
60
|
+
if ni := self._buf_news_by_ids.get(md.id):
|
|
61
|
+
ni.add_lang(md, post)
|
|
62
|
+
else:
|
|
63
|
+
ni = NewsItem(md.id)
|
|
64
|
+
ni.add_lang(md, post)
|
|
65
|
+
self._buf_news_by_ids[md.id] = ni
|
|
66
|
+
|
|
67
|
+
def finalize(self) -> None:
|
|
68
|
+
self._newsitems = list(self._buf_news_by_ids.values())
|
|
69
|
+
# sort in intended display order
|
|
70
|
+
self._newsitems.sort()
|
|
71
|
+
|
|
72
|
+
# mark the news item instances with ordinals
|
|
73
|
+
for i, ni in enumerate(self._newsitems):
|
|
74
|
+
ni.ordinal = i + 1
|
|
75
|
+
|
|
76
|
+
# also read statuses
|
|
77
|
+
for ni in self._newsitems:
|
|
78
|
+
ni.is_read = ni.id in self._rs_store
|
|
79
|
+
|
|
80
|
+
def list(self, only_unread: bool) -> list["NewsItem"]:
|
|
81
|
+
if not only_unread:
|
|
82
|
+
return self._newsitems
|
|
83
|
+
return [x for x in self._newsitems if not x.is_read]
|
|
84
|
+
|
|
85
|
+
def mark_as_read(self, *ids: str) -> None:
|
|
86
|
+
if not ids:
|
|
87
|
+
return
|
|
88
|
+
for id in ids:
|
|
89
|
+
self._rs_store.add(id)
|
|
90
|
+
self._rs_store.save()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@functools.total_ordering
|
|
94
|
+
class NewsItem:
|
|
95
|
+
def __init__(self, id: str) -> None:
|
|
96
|
+
self._id = id
|
|
97
|
+
self._content_by_lang: dict[str, NewsItemContent] = {}
|
|
98
|
+
|
|
99
|
+
# these fields are updated later in store initialization code
|
|
100
|
+
self.ordinal = 0
|
|
101
|
+
self.is_read = False
|
|
102
|
+
|
|
103
|
+
def __eq__(self, other: Any) -> bool:
|
|
104
|
+
if not isinstance(other, NewsItem):
|
|
105
|
+
return NotImplemented
|
|
106
|
+
return self._id == other._id and self.ordinal == other.ordinal
|
|
107
|
+
|
|
108
|
+
def __lt__(self, other: Any) -> bool:
|
|
109
|
+
if not isinstance(other, NewsItem):
|
|
110
|
+
return NotImplemented
|
|
111
|
+
return self._id < other._id or self.ordinal < other.ordinal
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def id(self) -> str:
|
|
115
|
+
return self._id
|
|
116
|
+
|
|
117
|
+
def __contains__(self, lang: str) -> bool:
|
|
118
|
+
return lang in self._content_by_lang
|
|
119
|
+
|
|
120
|
+
def __getitem__(self, lang: str) -> "NewsItemContent":
|
|
121
|
+
return self._content_by_lang[lang]
|
|
122
|
+
|
|
123
|
+
def add_lang(self, md: NewsItemNameMetadata, post: frontmatter.Post) -> None:
|
|
124
|
+
self._content_by_lang[md.lang] = NewsItemContent(md, post)
|
|
125
|
+
|
|
126
|
+
def __delitem__(self, lang: str) -> None:
|
|
127
|
+
del self._content_by_lang[lang]
|
|
128
|
+
|
|
129
|
+
def get_content_for_lang(self, lang: str) -> "NewsItemContent":
|
|
130
|
+
resolved_lang_code = match_lang_code(lang, self._content_by_lang.keys())
|
|
131
|
+
return self[resolved_lang_code]
|
|
132
|
+
|
|
133
|
+
def to_porcelain(self) -> "PorcelainNewsItemV1":
|
|
134
|
+
return {
|
|
135
|
+
"ty": PorcelainEntityType.NewsItemV1,
|
|
136
|
+
"id": self.id,
|
|
137
|
+
"ord": self.ordinal,
|
|
138
|
+
"is_read": self.is_read,
|
|
139
|
+
"langs": [x.to_porcelain() for x in self._content_by_lang.values()],
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class NewsItemContent:
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
md: NewsItemNameMetadata,
|
|
147
|
+
post: frontmatter.Post,
|
|
148
|
+
) -> None:
|
|
149
|
+
self._md = md
|
|
150
|
+
self._post = post
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def lang(self) -> str:
|
|
154
|
+
return self._md.lang
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def display_title(self) -> str:
|
|
158
|
+
metadata_title = self._post.get("title")
|
|
159
|
+
return metadata_title if isinstance(metadata_title, str) else self._md.id
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def content(self) -> str:
|
|
163
|
+
return self._post.content
|
|
164
|
+
|
|
165
|
+
def to_porcelain(self) -> "PorcelainNewsItemContentV1":
|
|
166
|
+
return {
|
|
167
|
+
"lang": self.lang,
|
|
168
|
+
"display_title": self.display_title,
|
|
169
|
+
"content": self.content,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class PorcelainNewsItemContentV1(TypedDict):
|
|
174
|
+
lang: str
|
|
175
|
+
display_title: str
|
|
176
|
+
content: str
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class PorcelainNewsItemV1(PorcelainEntity):
|
|
180
|
+
id: str
|
|
181
|
+
ord: int
|
|
182
|
+
is_read: bool
|
|
183
|
+
langs: list[PorcelainNewsItemContentV1]
|