maubot: update plugins

+250 -194
+108 -80
pkgs/tools/networking/maubot/plugins/generated.json
··· 66 } 67 }, 68 "github": { 69 - "hash": "sha256-O3FhZ6US4iACEzEKdHLjBZfOJlHNGEeLSrHdqWULFvk=", 70 "owner": "rom4nik", 71 "repo": "maubot-alternatingcaps", 72 - "rev": "v0.1.2" 73 }, 74 "manifest": { 75 "id": "pl.rom4nik.maubot.alternatingcaps", 76 "license": "MIT", 77 "main_class": "AlternatingCaps", 78 "modules": [ 79 "alternatingcaps" 80 ], 81 - "version": "0.1.2" 82 } 83 }, 84 "animemanga": { ··· 202 "version": "1.0.0" 203 } 204 }, 205 - "characterai": { 206 - "attrs": { 207 - "meta": { 208 - "changelog": "https://github.com/Matthieu-LAURENT39/maubot-characterai/releases", 209 - "description": "Chat with characters from [character.ai](https://character.ai/) in your Matrix rooms! Very customizable.", 210 - "downloadPage": "https://github.com/Matthieu-LAURENT39/maubot-characterai/releases", 211 - "homepage": "https://github.com/Matthieu-LAURENT39/maubot-characterai" 212 - } 213 - }, 214 - "github": { 215 - "hash": "sha256-nyVz0PDyNGAIFCxakWzEe8AG/PU+HlZJQQ85SL1bEvs=", 216 - "owner": "Matthieu-LAURENT39", 217 - "repo": "maubot-characterai", 218 - "rev": "v0.2.1" 219 - }, 220 - "manifest": { 221 - "config": true, 222 - "database": true, 223 - "database_type": "asyncpg", 224 - "dependencies": [ 225 - "characterai" 226 - ], 227 - "extra_files": [ 228 - "base-config.yaml" 229 - ], 230 - "id": "com.github.Matthieu-LAURENT39.maubot-characterai", 231 - "license": "MIT", 232 - "main_class": "CAIBot", 233 - "maubot": "0.1.0", 234 - "modules": [ 235 - "cai" 236 - ], 237 - "version": "0.2.1" 238 - } 239 - }, 240 "chatgpt": { 241 "attrs": { 242 "meta": { ··· 337 } 338 }, 339 "github": { 340 - "hash": "sha256-wO63G2mdpz2FWjatVY5R+L7Chki087Ev7oMfpgyOnxM=", 341 "owner": "williamkray", 342 "repo": "maubot-communitybot", 343 - "rev": "v0.1.7" 344 }, 345 "manifest": { 346 "database": true, ··· 355 "modules": [ 356 "community" 357 ], 358 - "version": "0.1.7" 359 } 360 }, 361 "dice": { ··· 542 } 543 }, 544 "github": { 545 - "hash": "sha256-VtZp4c3bbKCgbqQoJRnkle7Qn1zSGhgSPFAIlijQDOs=", 546 "owner": "williamkray", 547 "repo": "maubot-gifme", 548 - "rev": "a896a07fba53c90455431e79904f79d949c91f92" 549 }, 550 "manifest": { 551 "database": true, ··· 560 "modules": [ 561 "gifme" 562 ], 563 - "version": "0.1.0" 564 } 565 }, 566 "giphy": { ··· 603 } 604 }, 605 "github": { 606 - "hash": "sha256-Qc0KH8iGqMDa+1BXaB5fHtRIcsZRpTF2IufGMEXqV6Q=", 607 "owner": "maubot", 608 "repo": "github", 609 - "rev": "v0.1.2" 610 }, 611 "isOfficial": true, 612 "manifest": { ··· 618 "id": "xyz.maubot.github", 619 "license": "AGPL-3.0-or-later", 620 "main_class": "GitHubBot", 621 - "maubot": "0.3.0", 622 "modules": [ 623 "github" 624 ], 625 - "version": "0.1.2", 626 "webapp": true 627 } 628 }, ··· 796 "webapp": false 797 } 798 }, 799 "invite": { 800 "attrs": { 801 "meta": { ··· 867 } 868 }, 869 "github": { 870 - "hash": "sha256-6bggnk3196M0eCkfYTJWLhiIwIVTtluffQzc58yIYzw=", 871 "owner": "williamkray", 872 "repo": "maubot-join", 873 - "rev": "v0.3.1" 874 }, 875 "manifest": { 876 "database": false, ··· 884 "modules": [ 885 "join" 886 ], 887 - "version": "0.3.1" 888 } 889 }, 890 "karma": { ··· 1126 "description": "A plugin create Discourse forum post from messages in Matrix or Bridged rooms and perform advanced forum searches directly from Matrix or Bridged rooms. Perfect for community building and engagement.", 1127 "downloadPage": "https://github.com/gitayam/matrix-to-discourse/releases", 1128 "homepage": "https://github.com/gitayam/matrix-to-discourse" 1129 - } 1130 }, 1131 "github": { 1132 - "hash": "sha256-QIFgCQL9O/SVemXfxlXzPcPQ/qx68IU7ntArCk946iA=", 1133 "owner": "gitayam", 1134 "repo": "matrix-to-discourse", 1135 - "rev": "v0.1.0.1" 1136 }, 1137 "manifest": { 1138 "dependencies": [ 1139 - "aiohttp", 1140 - "maubot", 1141 - "mautrix", 1142 "openai", 1143 - "pyyaml", 1144 - "requests" 1145 ], 1146 - "id": "com.irregularchat.matrix_to_discourse", 1147 "license": "GPL-3.0", 1148 "main_class": "MatrixToDiscourseBot", 1149 "maubot": "0.1.0", 1150 "modules": [ 1151 - "bot" 1152 ], 1153 - "version": "0.1.0.0" 1154 } 1155 }, 1156 "media": { ··· 1214 } 1215 }, 1216 "gitlab": { 1217 - "hash": "sha256-6522dVqhGoPc/qjz65D3kXHks5LLb3yVe0K5abqdXrw=", 1218 "owner": "999eagle", 1219 "repo": "maubot-ntfy", 1220 - "rev": "256aa8f315cbb184eba0256c2ec818abbdd2d408" 1221 }, 1222 "manifest": { 1223 "config": true, ··· 1249 } 1250 }, 1251 "github": { 1252 - "hash": "sha256-vw2MT4pwmUUWolgzkq0nZ/YaAlKUANrN0NPXXFf7B1k=", 1253 "owner": "tcpipuk", 1254 "repo": "maubot-openai-translate", 1255 - "rev": "v0.3.1" 1256 }, 1257 "manifest": { 1258 "config": true, ··· 1266 "modules": [ 1267 "openaitranslate" 1268 ], 1269 - "version": "0.3.1" 1270 } 1271 }, 1272 "ovgumensabot": { ··· 1279 } 1280 }, 1281 "github": { 1282 - "hash": "sha256-nuOLUPwE0F15FgOtbq3+qmNNd2eHRrRNJPMM+v1Ksy0=", 1283 "owner": "v411e", 1284 "repo": "ovgumensabot", 1285 - "rev": "v0.0.8" 1286 }, 1287 "manifest": { 1288 "database": true, ··· 1300 "modules": [ 1301 "ovgumensabot" 1302 ], 1303 - "version": "0.0.8" 1304 } 1305 }, 1306 "pingcheck": { ··· 1395 "pretix-inviter": { 1396 "attrs": { 1397 "meta": { 1398 - "changelog": "https://github.com/fedora-infra/maubot-pretix-invite/blob/v0.3.2/CHANGELOG.md", 1399 "description": "A maubot plugin for inviting event participants from the pretix ticketing platform into a matrix room", 1400 "downloadPage": "https://github.com/fedora-infra/maubot-pretix-invite/releases", 1401 "homepage": "https://github.com/fedora-infra/maubot-pretix-invite" 1402 } 1403 }, 1404 "github": { 1405 - "hash": "sha256-KgWGvZ7QHcH0/u6+kodW8MAXtco4MM5MpbKscW903nQ=", 1406 "owner": "fedora-infra", 1407 "repo": "maubot-pretix-invite", 1408 - "rev": "v0.3.2" 1409 }, 1410 "manifest": { 1411 "config": true, ··· 1418 "modules": [ 1419 "event_helper" 1420 ], 1421 - "version": "0.3.2", 1422 "webapp": true 1423 } 1424 }, ··· 1654 } 1655 }, 1656 "github": { 1657 - "hash": "sha256-p/xJpJbzsOeQGcowvOhJSclPtmZyNyBaZBz+mexVqIY=", 1658 "owner": "maubot", 1659 "repo": "rss", 1660 - "rev": "v0.3.2" 1661 }, 1662 "isOfficial": true, 1663 "manifest": { ··· 1676 "modules": [ 1677 "rss" 1678 ], 1679 - "version": "0.3.2" 1680 } 1681 }, 1682 "satwcomic": { ··· 1783 } 1784 }, 1785 "github": { 1786 - "hash": "sha256-naHY6f034uGnPIHidI7WXjcf2h/t0IYaPkO5QfKkXMs=", 1787 "owner": "ggogel", 1788 "repo": "SocialMediaDownloadMaubot", 1789 - "rev": "1.4.2" 1790 }, 1791 "manifest": { 1792 "config": true, ··· 1802 "instaloader", 1803 "socialmediadownload" 1804 ], 1805 - "version": "1.4.2" 1806 } 1807 }, 1808 "songwhip": {
··· 66 } 67 }, 68 "github": { 69 + "hash": "sha256-RUwZ6SOsWiygyb10GnDmvskAurSiW9rFwDylYgr6wII=", 70 "owner": "rom4nik", 71 "repo": "maubot-alternatingcaps", 72 + "rev": "v0.1.3" 73 }, 74 "manifest": { 75 "id": "pl.rom4nik.maubot.alternatingcaps", 76 "license": "MIT", 77 "main_class": "AlternatingCaps", 78 + "maubot": "0.4.0", 79 "modules": [ 80 "alternatingcaps" 81 ], 82 + "version": "0.1.3" 83 } 84 }, 85 "animemanga": { ··· 203 "version": "1.0.0" 204 } 205 }, 206 "chatgpt": { 207 "attrs": { 208 "meta": { ··· 303 } 304 }, 305 "github": { 306 + "hash": "sha256-DNKdlbxeLdxb/OSujANzlZkgX1Bg6Q+4Ubxwq/0QV5M=", 307 "owner": "williamkray", 308 "repo": "maubot-communitybot", 309 + "rev": "v0.1.17" 310 }, 311 "manifest": { 312 "database": true, ··· 321 "modules": [ 322 "community" 323 ], 324 + "version": "0.1.17" 325 } 326 }, 327 "dice": { ··· 508 } 509 }, 510 "github": { 511 + "hash": "sha256-071iR5GlO+1WfMm6IK7by5nDfPhfOJCPr6WwB6qew/U=", 512 "owner": "williamkray", 513 "repo": "maubot-gifme", 514 + "rev": "v0.1.1" 515 }, 516 "manifest": { 517 "database": true, ··· 526 "modules": [ 527 "gifme" 528 ], 529 + "version": "0.1.1" 530 } 531 }, 532 "giphy": { ··· 569 } 570 }, 571 "github": { 572 + "hash": "sha256-XTX600ugWnaXyk1SFRwXWGCwRLcjXDBo1Vy0BG4kj5g=", 573 "owner": "maubot", 574 "repo": "github", 575 + "rev": "v0.2.0" 576 }, 577 "isOfficial": true, 578 "manifest": { ··· 584 "id": "xyz.maubot.github", 585 "license": "AGPL-3.0-or-later", 586 "main_class": "GitHubBot", 587 + "maubot": "0.4.1", 588 "modules": [ 589 "github" 590 ], 591 + "version": "0.2.0", 592 "webapp": true 593 } 594 }, ··· 762 "webapp": false 763 } 764 }, 765 + "idonthavespotify": { 766 + "attrs": { 767 + "meta": { 768 + "changelog": "https://github.com/HarHarLinks/maubot-idonthavespotify/releases", 769 + "description": "Reply to Spotify links with alternative streaming services.", 770 + "downloadPage": "https://github.com/HarHarLinks/maubot-idonthavespotify/releases", 771 + "homepage": "https://github.com/HarHarLinks/maubot-idonthavespotify" 772 + } 773 + }, 774 + "github": { 775 + "hash": "sha256-BFB/eyl1+I5P65RCSNYwEeitGCWBB8u7qpd70qLFJuY=", 776 + "owner": "HarHarLinks", 777 + "repo": "maubot-idonthavespotify", 778 + "rev": "v1.1.0" 779 + }, 780 + "manifest": { 781 + "config": true, 782 + "extra_files": [ 783 + "base-config.yaml" 784 + ], 785 + "id": "de.sosnowkadub.idonthavespotify", 786 + "license": "MIT", 787 + "main_class": "idonthavespotify/IDontHaveSpotifyPlugin", 788 + "maubot": "0.1.0", 789 + "modules": [ 790 + "idonthavespotify" 791 + ], 792 + "version": "1.1.0" 793 + } 794 + }, 795 "invite": { 796 "attrs": { 797 "meta": { ··· 863 } 864 }, 865 "github": { 866 + "hash": "sha256-ML4NEqn5fa/rBqzrocq0bUiktr81eyh4Uob5lJak+lk=", 867 "owner": "williamkray", 868 "repo": "maubot-join", 869 + "rev": "v0.3.2" 870 }, 871 "manifest": { 872 "database": false, ··· 880 "modules": [ 881 "join" 882 ], 883 + "version": "0.3.2" 884 } 885 }, 886 "karma": { ··· 1122 "description": "A plugin create Discourse forum post from messages in Matrix or Bridged rooms and perform advanced forum searches directly from Matrix or Bridged rooms. Perfect for community building and engagement.", 1123 "downloadPage": "https://github.com/gitayam/matrix-to-discourse/releases", 1124 "homepage": "https://github.com/gitayam/matrix-to-discourse" 1125 + }, 1126 + "postPatch": "cd plugin" 1127 }, 1128 "github": { 1129 + "hash": "sha256-GMLpfpNsDKX/3PPeWrHwMVq8ppygJTPY/QhKe1JDphE=", 1130 "owner": "gitayam", 1131 "repo": "matrix-to-discourse", 1132 + "rev": "v1.2.1" 1133 }, 1134 "manifest": { 1135 + "config": true, 1136 + "database": false, 1137 "dependencies": [ 1138 "openai", 1139 + "pyyaml" 1140 ], 1141 + "extra_files": [ 1142 + "base-config.yaml" 1143 + ], 1144 + "id": "url.irregularchat.matrix_to_discourse", 1145 "license": "GPL-3.0", 1146 "main_class": "MatrixToDiscourseBot", 1147 "maubot": "0.1.0", 1148 "modules": [ 1149 + "MatrixToDiscourseBot" 1150 ], 1151 + "version": "1.2.1" 1152 } 1153 }, 1154 "media": { ··· 1212 } 1213 }, 1214 "gitlab": { 1215 + "hash": "sha256-8Xsw/yO5Ma4weKAhk8DPQeCrn2ksk9c7J3oRzlAy2rw=", 1216 "owner": "999eagle", 1217 "repo": "maubot-ntfy", 1218 + "rev": "4e930c0e7100e06570707564fc471fc3c931708e" 1219 }, 1220 "manifest": { 1221 "config": true, ··· 1247 } 1248 }, 1249 "github": { 1250 + "hash": "sha256-PoHZhMy5sCgl1pf6xfbFpF0J9cSNk/NaVm6XeIgeAzU=", 1251 "owner": "tcpipuk", 1252 "repo": "maubot-openai-translate", 1253 + "rev": "v0.4.0" 1254 }, 1255 "manifest": { 1256 "config": true, ··· 1264 "modules": [ 1265 "openaitranslate" 1266 ], 1267 + "version": "0.4.0" 1268 } 1269 }, 1270 "ovgumensabot": { ··· 1277 } 1278 }, 1279 "github": { 1280 + "hash": "sha256-Gzw6YWvku0PbN/sNKABGjPPOpskubOHUVuiwMjD3m+c=", 1281 "owner": "v411e", 1282 "repo": "ovgumensabot", 1283 + "rev": "v0.0.9" 1284 }, 1285 "manifest": { 1286 "database": true, ··· 1298 "modules": [ 1299 "ovgumensabot" 1300 ], 1301 + "version": "0.0.9" 1302 } 1303 }, 1304 "pingcheck": { ··· 1393 "pretix-inviter": { 1394 "attrs": { 1395 "meta": { 1396 + "changelog": "https://github.com/fedora-infra/maubot-pretix-invite/blob/v0.4.1.1/CHANGELOG.md", 1397 "description": "A maubot plugin for inviting event participants from the pretix ticketing platform into a matrix room", 1398 "downloadPage": "https://github.com/fedora-infra/maubot-pretix-invite/releases", 1399 "homepage": "https://github.com/fedora-infra/maubot-pretix-invite" 1400 } 1401 }, 1402 "github": { 1403 + "hash": "sha256-3LfIh4THe9lGl2RJHuXA1SKJ9pvi8851F8n+HPSID+o=", 1404 "owner": "fedora-infra", 1405 "repo": "maubot-pretix-invite", 1406 + "rev": "v0.4.1.1" 1407 }, 1408 "manifest": { 1409 "config": true, ··· 1416 "modules": [ 1417 "event_helper" 1418 ], 1419 + "version": "0.4.1", 1420 "webapp": true 1421 } 1422 }, ··· 1652 } 1653 }, 1654 "github": { 1655 + "hash": "sha256-1Wac/j8qOTA31BCI4emOSYAEYEbtOjdB5ACz1qnY6h8=", 1656 "owner": "maubot", 1657 "repo": "rss", 1658 + "rev": "v0.4.1" 1659 }, 1660 "isOfficial": true, 1661 "manifest": { ··· 1674 "modules": [ 1675 "rss" 1676 ], 1677 + "version": "0.4.1" 1678 + } 1679 + }, 1680 + "rsvc": { 1681 + "attrs": { 1682 + "meta": { 1683 + "changelog": "https://github.com/maubot/rsvc/releases", 1684 + "description": "A bot to check the version of servers in room.", 1685 + "downloadPage": "https://github.com/maubot/rsvc/releases", 1686 + "homepage": "https://github.com/maubot/rsvc" 1687 + } 1688 + }, 1689 + "github": { 1690 + "hash": "sha256-4VvC2a0WZ9mlwV4l1Nz9eWatCy0nbhEXFhoAhUhrT1A=", 1691 + "owner": "maubot", 1692 + "repo": "rsvc", 1693 + "rev": "d67750085437fd50a6054bc1b6623b1a1341c0b8" 1694 + }, 1695 + "isOfficial": true, 1696 + "manifest": { 1697 + "extra_files": [ 1698 + "base-config.yaml" 1699 + ], 1700 + "id": "xyz.maubot.rsvc", 1701 + "license": "AGPL-3.0-or-later", 1702 + "main_class": "ServerCheckerBot", 1703 + "maubot": "0.1.0", 1704 + "modules": [ 1705 + "rsvc" 1706 + ], 1707 + "version": "1.0.0" 1708 } 1709 }, 1710 "satwcomic": { ··· 1811 } 1812 }, 1813 "github": { 1814 + "hash": "sha256-pea3NlDExMkgfWfP003xO5Nt+RnidpVq9PzDOxzz7Ow=", 1815 "owner": "ggogel", 1816 "repo": "SocialMediaDownloadMaubot", 1817 + "rev": "1.4.4" 1818 }, 1819 "manifest": { 1820 "config": true, ··· 1830 "instaloader", 1831 "socialmediadownload" 1832 ], 1833 + "version": "1.4.4" 1834 } 1835 }, 1836 "songwhip": {
+142 -114
pkgs/tools/networking/maubot/plugins/update.py
··· 10 import toml 11 import zipfile 12 13 - from typing import Dict, List 14 - 15 HOSTNAMES = { 16 - 'git.skeg1.se': 'gitlab', 17 - 'edugit.org': 'gitlab', 18 - 'codeberg.org': 'gitea', 19 } 20 - PLUGINS: Dict[str, dict] = {} 21 22 - yaml = ruamel.yaml.YAML(typ='safe') 23 24 - TMP = os.environ.get('TEMPDIR', '/tmp') 25 26 def process_repo(path: str, official: bool): 27 global PLUGINS 28 - with open(path, 'rt') as f: 29 data = yaml.load(f) 30 - name, repourl, license, desc = data['name'], data['repo'], data['license'], data['description'] 31 origurl = repourl 32 - if '/' in name or ' ' in name: 33 - name = os.path.split(path)[-1].removesuffix('.yaml') 34 - name = name.replace('_', '-').lower() 35 if name in PLUGINS.keys(): 36 - raise ValueError(f'Duplicate plugin {name}, refusing to continue') 37 - repodir = os.path.join(TMP, 'maubot-plugins', name) 38 plugindir = repodir 39 - if '/tree/' in repourl: 40 - repourl, rev_path = repourl.split('/tree/') 41 - rev, subdir = rev_path.strip('/').split('/') 42 plugindir = os.path.join(plugindir, subdir) 43 else: 44 rev = None 45 subdir = None 46 47 - if repourl.startswith('http:'): 48 - repourl = 'https' + repourl[4:] 49 - repourl = repourl.rstrip('/') 50 if not os.path.exists(repodir): 51 - print('Fetching', name) 52 - repo = git.Repo.clone_from(repourl + '.git', repodir) 53 else: 54 repo = git.Repo(repodir) 55 tags = sorted(repo.tags, key=lambda t: t.commit.committed_datetime) 56 - tags = list(filter(lambda x: 'rc' not in str(x), tags)) 57 if tags: 58 repo.git.checkout(tags[-1]) 59 rev = str(tags[-1]) 60 else: 61 - rev = str(repo.commit('HEAD')) 62 - ret: dict = {'attrs':{}} 63 if subdir: 64 - ret['attrs']['postPatch'] = f'cd {subdir}' 65 - domain, query = repourl.removeprefix('https://').split('/', 1) 66 - hash = subprocess.run([ 67 - 'nurl', 68 - '--hash', 69 - f'file://{repodir}', 70 - rev 71 - ], capture_output=True, check=True).stdout.decode('utf-8') 72 - ret['attrs']['meta'] = { 73 - 'description': desc, 74 - 'homepage': origurl, 75 } 76 - if domain == 'github.com': 77 - owner, repo = query.split('/') 78 - ret['github'] = { 79 - 'owner': owner, 80 - 'repo': repo, 81 - 'rev': rev, 82 - 'hash': hash, 83 } 84 - ret['attrs']['meta']['downloadPage'] = f'{repourl}/releases' 85 - ret['attrs']['meta']['changelog'] = f'{repourl}/releases' 86 - repobase = f'{repourl}/blob/{rev}' 87 - elif HOSTNAMES.get(domain, 'gitea' if 'gitea.' in domain or 'forgejo.' in domain else None) == 'gitea': 88 - owner, repo = query.split('/') 89 - ret['gitea'] = { 90 - 'domain': domain, 91 - 'owner': owner, 92 - 'repo': repo, 93 - 'rev': rev, 94 - 'hash': hash, 95 } 96 - repobase = f'{repourl}/src/commit/{rev}' 97 - ret['attrs']['meta']['downloadPage'] = f'{repourl}/releases' 98 - ret['attrs']['meta']['changelog'] = f'{repourl}/releases' 99 - elif HOSTNAMES.get(domain, 'gitlab' if 'gitlab.' in domain else None) == 'gitlab': 100 - owner, repo = query.split('/') 101 - ret['gitlab'] = { 102 - 'owner': owner, 103 - 'repo': repo, 104 - 'rev': rev, 105 - 'hash': hash, 106 } 107 - if domain != 'gitlab.com': 108 - ret['gitlab']['domain'] = domain 109 - repobase = f'{repourl}/-/blob/{rev}' 110 else: 111 - raise ValueError(f'Is {domain} Gitea or Gitlab, or something else? Please specify in the Python script!') 112 - if os.path.exists(os.path.join(plugindir, 'CHANGELOG.md')): 113 - ret['attrs']['meta']['changelog'] = f'{repobase}/CHANGELOG.md' 114 - if os.path.exists(os.path.join(plugindir, 'maubot.yaml')): 115 - with open(os.path.join(plugindir, 'maubot.yaml'), 'rt') as f: 116 - ret['manifest'] = yaml.load(f) 117 - elif os.path.exists(os.path.join(plugindir, 'pyproject.toml')): 118 - ret['isPoetry'] = True 119 - with open(os.path.join(plugindir, 'pyproject.toml'), 'rt') as f: 120 data = toml.load(f) 121 deps = [] 122 - for key, val in data['tool']['poetry'].get('dependencies', {}).items(): 123 - if key in ['maubot', 'mautrix', 'python']: 124 continue 125 reqs = [] 126 - for req in val.split(','): 127 reqs.extend(poetry_to_pep(req)) 128 - deps.append(key + ', '.join(reqs)) 129 - ret['manifest'] = data['tool']['maubot'] 130 - ret['manifest']['id'] = data['tool']['poetry']['name'] 131 - ret['manifest']['version'] = data['tool']['poetry']['version'] 132 - ret['manifest']['license'] = data['tool']['poetry']['license'] 133 if deps: 134 - ret['manifest']['dependencies'] = deps 135 else: 136 - raise ValueError(f'No maubot.yaml or pyproject.toml found in {repodir}') 137 # normalize non-spdx-conformant licenses this way 138 # (and fill out missing license info) 139 - if 'license' not in ret['manifest'] or ret['manifest']['license'] in ['GPLv3', 'AGPL 3.0']: 140 - ret['attrs']['meta']['license'] = license 141 - elif ret['manifest']['license'] != license: 142 - print(f"Warning: licenses for {repourl} don't match! {ret['manifest']['license']} != {license}") 143 if official: 144 - ret['isOfficial'] = official 145 PLUGINS[name] = ret 146 147 def next_incomp(ver_s: str) -> str: 148 - ver = ver_s.split('.') 149 zero = False 150 for i in range(len(ver)): 151 try: ··· 156 break 157 continue 158 if zero: 159 - ver[i] = '0' 160 elif seg: 161 ver[i] = str(seg + 1) 162 zero = True 163 - return '.'.join(ver) 164 165 - def poetry_to_pep(ver_req: str) -> List[str]: 166 - if '*' in ver_req: 167 - raise NotImplementedError('Wildcard poetry versions not implemented!') 168 - if ver_req.startswith('^'): 169 - return ['>=' + ver_req[1:], '<' + next_incomp(ver_req[1:])] 170 - if ver_req.startswith('~'): 171 - return ['~=' + ver_req[1:]] 172 return [ver_req] 173 174 def main(): 175 - cache_path = os.path.join(TMP, 'maubot-plugins') 176 if not os.path.exists(cache_path): 177 os.makedirs(cache_path) 178 - git.Repo.clone_from('https://github.com/maubot/plugins.maubot.xyz', os.path.join(cache_path, '_repo')) 179 else: 180 pass 181 182 - repodir = os.path.join(cache_path, '_repo') 183 184 - for suffix, official in (('official', True), ('thirdparty', False)): 185 - directory = os.path.join(repodir, 'data', 'plugins', suffix) 186 for plugin_name in os.listdir(directory): 187 process_repo(os.path.join(directory, plugin_name), official) 188 189 - if os.path.isdir('pkgs/tools/networking/maubot/plugins'): 190 - generated = 'pkgs/tools/networking/maubot/plugins/generated.json' 191 else: 192 script_dir = os.path.dirname(os.path.realpath(__file__)) 193 - generated = os.path.join(script_dir, 'generated.json') 194 195 - with open(generated, 'wt') as file: 196 - json.dump(PLUGINS, file, indent=' ', separators=(',', ': '), sort_keys=True) 197 - file.write('\n') 198 199 - if __name__ == '__main__': 200 main()
··· 10 import toml 11 import zipfile 12 13 HOSTNAMES = { 14 + "git.skeg1.se": "gitlab", 15 + "edugit.org": "gitlab", 16 + "codeberg.org": "gitea", 17 } 18 + PLUGINS: dict[str, dict] = {} 19 + # https://github.com/maubot/plugins.maubot.xyz/pull/45 20 + SKIP = {"characterai"} 21 + DIRS = {"matrix-to-discourse": "plugin"} 22 23 + yaml = ruamel.yaml.YAML(typ="safe") 24 25 + TMP = os.environ.get("TEMPDIR", "/tmp") 26 + 27 28 def process_repo(path: str, official: bool): 29 global PLUGINS 30 + with open(path, "rt") as f: 31 data = yaml.load(f) 32 + name, repourl, license, desc = ( 33 + data["name"], 34 + data["repo"], 35 + data["license"], 36 + data["description"], 37 + ) 38 + if name in SKIP: 39 + return 40 origurl = repourl 41 + if "/" in name or " " in name: 42 + name = os.path.split(path)[-1].removesuffix(".yaml") 43 + name = name.replace("_", "-").lower() 44 if name in PLUGINS.keys(): 45 + raise ValueError(f"Duplicate plugin {name}, refusing to continue") 46 + repodir = os.path.join(TMP, "maubot-plugins", name) 47 plugindir = repodir 48 + if "/tree/" in repourl: 49 + repourl, rev_path = repourl.split("/tree/") 50 + rev, subdir = rev_path.strip("/").split("/") 51 + plugindir = os.path.join(plugindir, subdir) 52 + elif name in DIRS.keys(): 53 + subdir = DIRS[name] 54 plugindir = os.path.join(plugindir, subdir) 55 else: 56 rev = None 57 subdir = None 58 59 + if repourl.startswith("http:"): 60 + repourl = "https" + repourl[4:] 61 + repourl = repourl.rstrip("/") 62 if not os.path.exists(repodir): 63 + print("Fetching", name) 64 + repo = git.Repo.clone_from(repourl + ".git", repodir) 65 else: 66 repo = git.Repo(repodir) 67 tags = sorted(repo.tags, key=lambda t: t.commit.committed_datetime) 68 + tags = list(filter(lambda x: "rc" not in str(x), tags)) 69 if tags: 70 repo.git.checkout(tags[-1]) 71 rev = str(tags[-1]) 72 else: 73 + rev = str(repo.commit("HEAD")) 74 + ret: dict = {"attrs": {}} 75 if subdir: 76 + ret["attrs"]["postPatch"] = f"cd {subdir}" 77 + domain, query = repourl.removeprefix("https://").split("/", 1) 78 + hash = subprocess.run( 79 + ["nurl", "--hash", f"file://{repodir}", rev], capture_output=True, check=True 80 + ).stdout.decode("utf-8") 81 + ret["attrs"]["meta"] = { 82 + "description": desc, 83 + "homepage": origurl, 84 } 85 + if domain == "github.com": 86 + owner, repo = query.split("/") 87 + ret["github"] = { 88 + "owner": owner, 89 + "repo": repo, 90 + "rev": rev, 91 + "hash": hash, 92 } 93 + ret["attrs"]["meta"]["downloadPage"] = f"{repourl}/releases" 94 + ret["attrs"]["meta"]["changelog"] = f"{repourl}/releases" 95 + repobase = f"{repourl}/blob/{rev}" 96 + elif ( 97 + HOSTNAMES.get( 98 + domain, "gitea" if "gitea." in domain or "forgejo." in domain else None 99 + ) 100 + == "gitea" 101 + ): 102 + owner, repo = query.split("/") 103 + ret["gitea"] = { 104 + "domain": domain, 105 + "owner": owner, 106 + "repo": repo, 107 + "rev": rev, 108 + "hash": hash, 109 } 110 + repobase = f"{repourl}/src/commit/{rev}" 111 + ret["attrs"]["meta"]["downloadPage"] = f"{repourl}/releases" 112 + ret["attrs"]["meta"]["changelog"] = f"{repourl}/releases" 113 + elif HOSTNAMES.get(domain, "gitlab" if "gitlab." in domain else None) == "gitlab": 114 + owner, repo = query.split("/") 115 + ret["gitlab"] = { 116 + "owner": owner, 117 + "repo": repo, 118 + "rev": rev, 119 + "hash": hash, 120 } 121 + if domain != "gitlab.com": 122 + ret["gitlab"]["domain"] = domain 123 + repobase = f"{repourl}/-/blob/{rev}" 124 else: 125 + raise ValueError( 126 + f"Is {domain} Gitea or Gitlab, or something else? Please specify in the Python script!" 127 + ) 128 + if os.path.exists(os.path.join(plugindir, "CHANGELOG.md")): 129 + ret["attrs"]["meta"]["changelog"] = f"{repobase}/CHANGELOG.md" 130 + if os.path.exists(os.path.join(plugindir, "maubot.yaml")): 131 + with open(os.path.join(plugindir, "maubot.yaml"), "rt") as f: 132 + ret["manifest"] = yaml.load(f) 133 + elif os.path.exists(os.path.join(plugindir, "pyproject.toml")): 134 + ret["isPoetry"] = True 135 + with open(os.path.join(plugindir, "pyproject.toml"), "rt") as f: 136 data = toml.load(f) 137 deps = [] 138 + for key, val in data["tool"]["poetry"].get("dependencies", {}).items(): 139 + if key in ["maubot", "mautrix", "python"]: 140 continue 141 reqs = [] 142 + for req in val.split(","): 143 reqs.extend(poetry_to_pep(req)) 144 + deps.append(key + ", ".join(reqs)) 145 + ret["manifest"] = data["tool"]["maubot"] 146 + ret["manifest"]["id"] = data["tool"]["poetry"]["name"] 147 + ret["manifest"]["version"] = data["tool"]["poetry"]["version"] 148 + ret["manifest"]["license"] = data["tool"]["poetry"]["license"] 149 if deps: 150 + ret["manifest"]["dependencies"] = deps 151 else: 152 + raise ValueError(f"No maubot.yaml or pyproject.toml found in {repodir}") 153 # normalize non-spdx-conformant licenses this way 154 # (and fill out missing license info) 155 + if "license" not in ret["manifest"] or ret["manifest"]["license"] in [ 156 + "GPLv3", 157 + "AGPL 3.0", 158 + ]: 159 + ret["attrs"]["meta"]["license"] = license 160 + elif ret["manifest"]["license"] != license: 161 + print( 162 + f"Warning: licenses for {repourl} don't match! {ret['manifest']['license']} != {license}" 163 + ) 164 if official: 165 + ret["isOfficial"] = official 166 PLUGINS[name] = ret 167 + 168 169 def next_incomp(ver_s: str) -> str: 170 + ver = ver_s.split(".") 171 zero = False 172 for i in range(len(ver)): 173 try: ··· 178 break 179 continue 180 if zero: 181 + ver[i] = "0" 182 elif seg: 183 ver[i] = str(seg + 1) 184 zero = True 185 + return ".".join(ver) 186 187 + 188 + def poetry_to_pep(ver_req: str) -> list[str]: 189 + if "*" in ver_req: 190 + raise NotImplementedError("Wildcard poetry versions not implemented!") 191 + if ver_req.startswith("^"): 192 + return [">=" + ver_req[1:], "<" + next_incomp(ver_req[1:])] 193 + if ver_req.startswith("~"): 194 + return ["~=" + ver_req[1:]] 195 return [ver_req] 196 + 197 198 def main(): 199 + cache_path = os.path.join(TMP, "maubot-plugins") 200 if not os.path.exists(cache_path): 201 os.makedirs(cache_path) 202 + git.Repo.clone_from( 203 + "https://github.com/maubot/plugins.maubot.xyz", 204 + os.path.join(cache_path, "_repo"), 205 + ) 206 else: 207 pass 208 209 + repodir = os.path.join(cache_path, "_repo") 210 211 + for suffix, official in (("official", True), ("thirdparty", False)): 212 + directory = os.path.join(repodir, "data", "plugins", suffix) 213 for plugin_name in os.listdir(directory): 214 process_repo(os.path.join(directory, plugin_name), official) 215 216 + if os.path.isdir("pkgs/tools/networking/maubot/plugins"): 217 + generated = "pkgs/tools/networking/maubot/plugins/generated.json" 218 else: 219 script_dir = os.path.dirname(os.path.realpath(__file__)) 220 + generated = os.path.join(script_dir, "generated.json") 221 222 + with open(generated, "wt") as file: 223 + json.dump(PLUGINS, file, indent=" ", separators=(",", ": "), sort_keys=True) 224 + file.write("\n") 225 226 + 227 + if __name__ == "__main__": 228 main()