jetbrains-plugin-server 0.0.1__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.
- jetbrains_plugin_server/__init__.py +1 -0
- jetbrains_plugin_server/config.py +20 -0
- jetbrains_plugin_server/model/__init__.py +0 -0
- jetbrains_plugin_server/model/data_listing.py +50 -0
- jetbrains_plugin_server/plugin_catalog.py +18 -0
- jetbrains_plugin_server/plugin_model.py +35 -0
- jetbrains_plugin_server/schemas.py +63 -0
- jetbrains_plugin_server/server.py +41 -0
- jetbrains_plugin_server/to_xml.py +29 -0
- jetbrains_plugin_server/tools/__init__.py +0 -0
- jetbrains_plugin_server/tools/dl_data.py +55 -0
- jetbrains_plugin_server/tools/gen_json_cache.py +71 -0
- jetbrains_plugin_server-0.0.1.dist-info/METADATA +44 -0
- jetbrains_plugin_server-0.0.1.dist-info/RECORD +17 -0
- jetbrains_plugin_server-0.0.1.dist-info/WHEEL +5 -0
- jetbrains_plugin_server-0.0.1.dist-info/licenses/LICENSE.md +21 -0
- jetbrains_plugin_server-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.0.1'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
DL_URL_BASE = os.getenv("DL_URL_BASE", "https://fake.url/{plugin_version_id}")
|
|
5
|
+
|
|
6
|
+
JETBRAINS_PLUGINS_HOST = "https://plugins.jetbrains.com"
|
|
7
|
+
|
|
8
|
+
LOCAL = Path(__file__).parent.parent.joinpath("local")
|
|
9
|
+
|
|
10
|
+
PLUGIN_PROD_DATA = Path(__file__).parent.parent.joinpath("plugins_prod.json")
|
|
11
|
+
|
|
12
|
+
PLUGIN_TEST_DATA = Path(__file__).parent.parent.joinpath("tests", "data", "plugins_test.json")
|
|
13
|
+
|
|
14
|
+
PLUGIN_SPECS_DIR = "plugin_specs"
|
|
15
|
+
PLUGIN_VERSIONS_DIR = "plugin_versions"
|
|
16
|
+
PLUGINS_DIR = "plugins"
|
|
17
|
+
|
|
18
|
+
IS_TEST_MODE = os.getenv("TEST_MODE") == "true"
|
|
19
|
+
|
|
20
|
+
FAST_API_OFFLINE = os.getenv("FAST_API_OFFLINE") == "true"
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataListing(ABC):
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def list(self, directory) -> list[str]:
|
|
11
|
+
raise NotImplementedError()
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def get(self, directory, file) -> Any:
|
|
15
|
+
raise NotImplementedError()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FSDataListing(DataListing):
|
|
19
|
+
|
|
20
|
+
def __init__(self, base_path: str | Path):
|
|
21
|
+
self.base_path = Path(base_path)
|
|
22
|
+
|
|
23
|
+
def list(self, directory) -> list[str]:
|
|
24
|
+
return [
|
|
25
|
+
p.name
|
|
26
|
+
for p in self.base_path.joinpath(directory).glob("*")
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
def get(self, directory, file) -> Any:
|
|
30
|
+
return self.base_path.joinpath(directory, file).read_text(encoding="utf8")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ArtifactoryDataListing(DataListing):
|
|
34
|
+
|
|
35
|
+
def __init__(self, base_url: str, repo_name: str):
|
|
36
|
+
self.base_url = base_url.strip("/")
|
|
37
|
+
self.repo_name = repo_name.strip("/")
|
|
38
|
+
|
|
39
|
+
def list(self, directory) -> list[str]:
|
|
40
|
+
url = f"{self.base_url}/artifactory/api/storage/{self.repo_name}/{directory}"
|
|
41
|
+
files_rep = requests.get(url)
|
|
42
|
+
files = files_rep.json()
|
|
43
|
+
return [
|
|
44
|
+
Path(file["uri"]).name
|
|
45
|
+
for file in files["children"]
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
def get(self, directory, file) -> Any:
|
|
49
|
+
url = f"{self.base_url}/artifactory/{self.repo_name}/{directory}/{file}"
|
|
50
|
+
return requests.get(url).text
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
|
|
5
|
+
from jetbrains_plugin_server.config import PLUGIN_TEST_DATA, IS_TEST_MODE, PLUGIN_PROD_DATA
|
|
6
|
+
from jetbrains_plugin_server.schemas import CatalogSchema
|
|
7
|
+
|
|
8
|
+
LOG = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@lru_cache()
|
|
12
|
+
def get_plugin_catalog() -> CatalogSchema:
|
|
13
|
+
LOG.info("load catalog from file")
|
|
14
|
+
if IS_TEST_MODE:
|
|
15
|
+
catalog_path = PLUGIN_TEST_DATA
|
|
16
|
+
else:
|
|
17
|
+
catalog_path = PLUGIN_PROD_DATA
|
|
18
|
+
return CatalogSchema.model_validate(json.loads(catalog_path.read_text()))
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from pydantic_extra_types.semantic_version import SemanticVersion
|
|
2
|
+
|
|
3
|
+
from jetbrains_plugin_server.plugin_catalog import get_plugin_catalog
|
|
4
|
+
from jetbrains_plugin_server.schemas import PluginVersionSchema, LowPaddingSemanticVersion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_plugins(build: str) -> list[tuple[str, PluginVersionSchema]]:
|
|
8
|
+
catalog = get_plugin_catalog()
|
|
9
|
+
build_version = LowPaddingSemanticVersion.parse(build)
|
|
10
|
+
return [
|
|
11
|
+
(plugin.name, version_found)
|
|
12
|
+
for plugin in catalog.plugins
|
|
13
|
+
if (version_found := get_latest_compatible(build_version, plugin.versions))
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_latest_compatible(
|
|
18
|
+
build_version: SemanticVersion,
|
|
19
|
+
plugin_versions: list[PluginVersionSchema]
|
|
20
|
+
):
|
|
21
|
+
for plugin_version in plugin_versions:
|
|
22
|
+
if is_compatible(build_version, plugin_version):
|
|
23
|
+
return plugin_version
|
|
24
|
+
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_compatible(
|
|
29
|
+
build_version: SemanticVersion,
|
|
30
|
+
plugin_version: PluginVersionSchema
|
|
31
|
+
) -> bool:
|
|
32
|
+
since, until = plugin_version.specs.since_build_semver, plugin_version.specs.until_build_semver
|
|
33
|
+
if until:
|
|
34
|
+
return since <= build_version <= until
|
|
35
|
+
return since <= build_version
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Literal, Type, Any
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, model_validator
|
|
5
|
+
from pydantic_extra_types.semantic_version import SemanticVersion
|
|
6
|
+
from semver._types import String
|
|
7
|
+
from semver.version import T
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LowPaddingSemanticVersion:
|
|
11
|
+
@staticmethod
|
|
12
|
+
def parse(version: str) -> SemanticVersion:
|
|
13
|
+
return SemanticVersion.parse(normalize_version(version, "start"))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HighPaddingSemanticVersion:
|
|
17
|
+
@staticmethod
|
|
18
|
+
def parse(version: str) -> SemanticVersion:
|
|
19
|
+
return SemanticVersion.parse(normalize_version(version, "end"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def normalize_version(value: str, mode: Literal["start", "end"]):
|
|
23
|
+
if match := re.match(r"^[A-Z]+-(.+)$", value):
|
|
24
|
+
value = match.group(1)
|
|
25
|
+
replacer = "0" if mode == "start" else "999999"
|
|
26
|
+
result = value.replace(".*", f".{replacer}")
|
|
27
|
+
while result.count(".") < 2:
|
|
28
|
+
result += f".{replacer}"
|
|
29
|
+
return result
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PluginVersionSpecSchema(BaseModel):
|
|
33
|
+
since_build: str = Field(alias="since-build")
|
|
34
|
+
until_build: str | None = Field(alias="until-build", default=None)
|
|
35
|
+
|
|
36
|
+
since_build_semver: SemanticVersion = Field(alias="since-build-semver")
|
|
37
|
+
until_build_semver: SemanticVersion | None = Field(alias="until-build-semver", default=None)
|
|
38
|
+
|
|
39
|
+
@model_validator(mode='before')
|
|
40
|
+
@classmethod
|
|
41
|
+
def set_semver_fields(cls, data: Any) -> Any:
|
|
42
|
+
data["since-build-semver"] = LowPaddingSemanticVersion.parse(data["since-build"])
|
|
43
|
+
if ub := data.get("until-build"):
|
|
44
|
+
data["until-build-semver"] = HighPaddingSemanticVersion.parse(ub)
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PluginVersionSchema(BaseModel):
|
|
49
|
+
plugin_id: str
|
|
50
|
+
plugin_version_id: int
|
|
51
|
+
description: str | None
|
|
52
|
+
change_notes: str | None
|
|
53
|
+
version: str
|
|
54
|
+
specs: PluginVersionSpecSchema
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class PluginSchema(BaseModel):
|
|
58
|
+
name: str
|
|
59
|
+
versions: list[PluginVersionSchema]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class CatalogSchema(BaseModel):
|
|
63
|
+
plugins: list[PluginSchema] = Field(default_factory=list)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import markdown
|
|
6
|
+
|
|
7
|
+
from jetbrains_plugin_server.config import FAST_API_OFFLINE
|
|
8
|
+
|
|
9
|
+
if FAST_API_OFFLINE:
|
|
10
|
+
from fastapi_offline import FastAPIOffline as FastAPI
|
|
11
|
+
else:
|
|
12
|
+
from fastapi import FastAPI # type: ignore
|
|
13
|
+
|
|
14
|
+
from fastapi.responses import HTMLResponse, Response
|
|
15
|
+
|
|
16
|
+
from jetbrains_plugin_server.plugin_catalog import get_plugin_catalog
|
|
17
|
+
from jetbrains_plugin_server.plugin_model import get_plugins
|
|
18
|
+
from jetbrains_plugin_server.to_xml import to_xml
|
|
19
|
+
|
|
20
|
+
LOG = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_app():
|
|
24
|
+
app = FastAPI()
|
|
25
|
+
|
|
26
|
+
@app.get("/")
|
|
27
|
+
def get_plugins_route(build: Annotated[
|
|
28
|
+
str, "IDE build number to filter the available plugins and return only the compatible ones"] = ""):
|
|
29
|
+
if not build:
|
|
30
|
+
md = Path(__file__).parent.parent.joinpath("README.md").read_text()
|
|
31
|
+
return HTMLResponse(content=markdown.markdown(md))
|
|
32
|
+
|
|
33
|
+
LOG.debug("Request with build=%s", build)
|
|
34
|
+
result = get_plugins(build)
|
|
35
|
+
return Response(content=to_xml(result), media_type="application/xml")
|
|
36
|
+
|
|
37
|
+
@app.get("/cache")
|
|
38
|
+
def get_cache_route():
|
|
39
|
+
return get_plugin_catalog()
|
|
40
|
+
|
|
41
|
+
return app
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import xml.etree.ElementTree as ET
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
|
|
4
|
+
from jetbrains_plugin_server.config import DL_URL_BASE
|
|
5
|
+
from jetbrains_plugin_server.schemas import PluginVersionSchema
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def to_xml(plugins: list[tuple[str, PluginVersionSchema]]):
|
|
9
|
+
a = ET.Element('plugins')
|
|
10
|
+
for name, plugin in plugins:
|
|
11
|
+
p = ET.SubElement(a, 'plugin', {
|
|
12
|
+
"id": plugin.plugin_id,
|
|
13
|
+
# url of download
|
|
14
|
+
"url": DL_URL_BASE.format(plugin_version_id=plugin.plugin_version_id),
|
|
15
|
+
"version": plugin.version
|
|
16
|
+
})
|
|
17
|
+
attrs = {"since-build": plugin.specs.since_build}
|
|
18
|
+
if ub := plugin.specs.until_build:
|
|
19
|
+
attrs["until-build"] = ub
|
|
20
|
+
iv = ET.SubElement(p, 'idea-version', attrs)
|
|
21
|
+
|
|
22
|
+
ET.SubElement(p, 'name').text = name
|
|
23
|
+
ET.SubElement(p, 'description').text = plugin.description
|
|
24
|
+
ET.SubElement(p, 'change-notes').text = plugin.change_notes
|
|
25
|
+
|
|
26
|
+
bio = BytesIO()
|
|
27
|
+
ET.ElementTree(a).write(bio)
|
|
28
|
+
bio.seek(0)
|
|
29
|
+
return b"<?xml version='1.0' encoding='UTF-8'?>" + bio.read()
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from requests import get, Session
|
|
2
|
+
from requests.adapters import HTTPAdapter, Retry
|
|
3
|
+
|
|
4
|
+
from jetbrains_plugin_server.config import PLUGINS_DIR, PLUGIN_VERSIONS_DIR, PLUGIN_SPECS_DIR, LOCAL, \
|
|
5
|
+
JETBRAINS_PLUGINS_HOST
|
|
6
|
+
|
|
7
|
+
PLUGINS: list[str] = [
|
|
8
|
+
"https://plugins.jetbrains.com/plugin/631-python",
|
|
9
|
+
"https://plugins.jetbrains.com/plugin/10080-rainbow-brackets",
|
|
10
|
+
"https://plugins.jetbrains.com/plugin/11938-one-dark-theme",
|
|
11
|
+
"https://plugins.jetbrains.com/plugin/9525--env-files",
|
|
12
|
+
"https://plugins.jetbrains.com/plugin/11938-one-dark-theme",
|
|
13
|
+
"https://plugins.jetbrains.com/plugin/15075-jpa-buddy",
|
|
14
|
+
"https://plugins.jetbrains.com/plugin/9525--env-files-support/",
|
|
15
|
+
"https://plugins.jetbrains.com/plugin/10044-atom-material-icons/",
|
|
16
|
+
"https://plugins.jetbrains.com/plugin/164-ideavim",
|
|
17
|
+
"https://plugins.jetbrains.com/plugin/9792-key-promoter-x",
|
|
18
|
+
"https://plugins.jetbrains.com/plugin/14708-mario-progress-bar",
|
|
19
|
+
"https://plugins.jetbrains.com/plugin/7086-acejump"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
if __name__ == '__main__':
|
|
23
|
+
s = Session()
|
|
24
|
+
retries = Retry(total=5, backoff_factor=0.1)
|
|
25
|
+
s.mount('https://', HTTPAdapter(max_retries=retries))
|
|
26
|
+
|
|
27
|
+
for plugin in PLUGINS:
|
|
28
|
+
print("PLUGIN", plugin)
|
|
29
|
+
plugin = plugin.replace(f"{JETBRAINS_PLUGINS_HOST}/plugin/", "").strip("/")
|
|
30
|
+
plugin_id_int = plugin.split("-", maxsplit=1)[0]
|
|
31
|
+
|
|
32
|
+
versions_rep = get(f"{JETBRAINS_PLUGINS_HOST}/plugins/list?pluginId={plugin}")
|
|
33
|
+
LOCAL.joinpath(PLUGIN_SPECS_DIR, f"{plugin_id_int}.xml").write_bytes(
|
|
34
|
+
versions_rep.content
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
versions_id_rep = get(f"{JETBRAINS_PLUGINS_HOST}/api/plugins/{plugin_id_int}/updateVersions")
|
|
38
|
+
LOCAL.joinpath(PLUGIN_VERSIONS_DIR, f"{plugin_id_int}.json").write_bytes(
|
|
39
|
+
versions_id_rep.content
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
for row in versions_id_rep.json()[:-4:-1]:
|
|
43
|
+
print(" VERSION", row["version"])
|
|
44
|
+
plugin_version_id = row["id"]
|
|
45
|
+
dl = s.get(
|
|
46
|
+
f"{JETBRAINS_PLUGINS_HOST}/plugin/download",
|
|
47
|
+
params={"updateId": plugin_version_id},
|
|
48
|
+
stream=True
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
print(" Done in ", dl.elapsed)
|
|
52
|
+
|
|
53
|
+
LOCAL.joinpath(PLUGINS_DIR, f"{plugin_version_id}.zip").write_bytes(
|
|
54
|
+
dl.content
|
|
55
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import xml.etree.ElementTree as ET
|
|
4
|
+
from typing import cast
|
|
5
|
+
|
|
6
|
+
from jetbrains_plugin_server.config import PLUGIN_TEST_DATA, PLUGIN_SPECS_DIR, PLUGIN_VERSIONS_DIR, \
|
|
7
|
+
PLUGIN_PROD_DATA, IS_TEST_MODE, \
|
|
8
|
+
PLUGINS_DIR
|
|
9
|
+
from jetbrains_plugin_server.model.data_listing import DataListing
|
|
10
|
+
from jetbrains_plugin_server.schemas import CatalogSchema, PluginSchema, PluginVersionSchema, \
|
|
11
|
+
PluginVersionSpecSchema
|
|
12
|
+
|
|
13
|
+
LOG = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def gen_json_cache(dl: DataListing, only_available_plugins: bool = True):
|
|
17
|
+
"""
|
|
18
|
+
dl = ArtifactoryDataListing("https://...", "jetbrains/plugin-server")
|
|
19
|
+
dl = FSDataListing(LOCAL)
|
|
20
|
+
|
|
21
|
+
gen_json_cache(dl)
|
|
22
|
+
"""
|
|
23
|
+
LOG.info("build catalog")
|
|
24
|
+
|
|
25
|
+
result: CatalogSchema = CatalogSchema()
|
|
26
|
+
|
|
27
|
+
available_plugins = [int(p.split(".", maxsplit=1)[0]) for p in dl.list(PLUGINS_DIR)]
|
|
28
|
+
|
|
29
|
+
for plugin in dl.list(PLUGIN_SPECS_DIR):
|
|
30
|
+
plugin_id_int = plugin.split(".", maxsplit=1)[0]
|
|
31
|
+
|
|
32
|
+
versions_to_plugin_version_id = {
|
|
33
|
+
row["version"]: row["id"]
|
|
34
|
+
for row in json.loads(dl.get(PLUGIN_VERSIONS_DIR, f"{plugin_id_int}.json"))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
plugin_spec = dl.get(PLUGIN_SPECS_DIR, plugin)
|
|
38
|
+
|
|
39
|
+
root = ET.fromstring(plugin_spec)
|
|
40
|
+
|
|
41
|
+
if not (category := root.find("category")):
|
|
42
|
+
LOG.error("Plugin %s has no category", plugin)
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
versions = category.findall("idea-plugin")
|
|
46
|
+
|
|
47
|
+
result.plugins.append(PluginSchema(
|
|
48
|
+
name=versions[0].find("name").text,
|
|
49
|
+
versions=[
|
|
50
|
+
PluginVersionSchema(
|
|
51
|
+
plugin_id=version.find("id").text,
|
|
52
|
+
plugin_version_id=versions_to_plugin_version_id[version.find("version").text],
|
|
53
|
+
version=version.find("version").text or "",
|
|
54
|
+
specs=PluginVersionSpecSchema(
|
|
55
|
+
**{cast(str, k): v for k, v in version.find("idea-version").items() if v != "n/a"}
|
|
56
|
+
),
|
|
57
|
+
description=version.find("description").text,
|
|
58
|
+
change_notes=version.find("change-notes").text,
|
|
59
|
+
)
|
|
60
|
+
for version in versions
|
|
61
|
+
if not only_available_plugins or
|
|
62
|
+
versions_to_plugin_version_id[version.find("version").text] in available_plugins
|
|
63
|
+
]
|
|
64
|
+
))
|
|
65
|
+
LOG.info("Plugin '%s' (%s) found %s versions but only %s had available zip",
|
|
66
|
+
versions[0].find("name").text, plugin, len(versions), len(result.plugins[-1].versions))
|
|
67
|
+
|
|
68
|
+
if IS_TEST_MODE:
|
|
69
|
+
PLUGIN_TEST_DATA.write_text(json.dumps(result.model_dump(mode="json", by_alias=True), indent=4))
|
|
70
|
+
else:
|
|
71
|
+
PLUGIN_PROD_DATA.write_text(json.dumps(result.model_dump(mode="json", by_alias=True), indent=4))
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jetbrains-plugin-server
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A server to serve jetbrains plugins
|
|
5
|
+
Author-email: azro352 <35503478+azro352@users.noreply.github.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/azro352/jetbrains-plugin-server.git
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/azro352/jetbrains-plugin-server/issues
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.md
|
|
18
|
+
Requires-Dist: fastapi~=0.115.12
|
|
19
|
+
Requires-Dist: markdown~=3.8
|
|
20
|
+
Requires-Dist: parameterized~=0.9.0
|
|
21
|
+
Requires-Dist: pydantic~=2.11.3
|
|
22
|
+
Requires-Dist: pydantic-extra-types[semver]~=2.10.3
|
|
23
|
+
Requires-Dist: requests~=2.32.3
|
|
24
|
+
Requires-Dist: semver~=3.0.4
|
|
25
|
+
Requires-Dist: uvicorn
|
|
26
|
+
Provides-Extra: offline
|
|
27
|
+
Requires-Dist: fastapi_offline; extra == "offline"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<!--
|
|
31
|
+
|
|
32
|
+
THIS README FILE IS RENDERED ON '/' ENDPOINT WHEN NO "build" ARG IS GIVEN
|
|
33
|
+
|
|
34
|
+
-->
|
|
35
|
+
|
|
36
|
+
# jetbrains-plugin-server
|
|
37
|
+
|
|
38
|
+
Creates a jetbrains-compatible plugin server with a given list of plugins
|
|
39
|
+
|
|
40
|
+
## Tools
|
|
41
|
+
|
|
42
|
+
- `src/tools/dl_data.py` to fetch plugins specifications, versions and content from jetbrains to a local filesystem
|
|
43
|
+
- `src/tools/gen_json_cache.py` to build a JSON cache to answer faster, using either a filesystem storage or an
|
|
44
|
+
artifactory
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
jetbrains_plugin_server/__init__.py,sha256=DsAHdxLC16H2VjdFOU5tBx2xT9VnNQ-XbTS24fRCa_w,22
|
|
2
|
+
jetbrains_plugin_server/config.py,sha256=g684QHR0SnHADEKC6EuWWUIXPqthr1wNw83uciMvP3o,612
|
|
3
|
+
jetbrains_plugin_server/plugin_catalog.py,sha256=k8Lfd-77JBll39JE4H4q6U3KO9FHTFB2yfAnqRcTglw,531
|
|
4
|
+
jetbrains_plugin_server/plugin_model.py,sha256=_8qVxqTPxQUaYvLDp7Or85kZI1NdCX8JnP3j358vYj4,1157
|
|
5
|
+
jetbrains_plugin_server/schemas.py,sha256=mYlyIidhAYpafmRn0M1j4ouNQNgGZZtgARsbwL66nuM,1967
|
|
6
|
+
jetbrains_plugin_server/server.py,sha256=zQlnoP_qOOn4meYBPu4SDy4xXiBJKvxLABan88tFBPo,1196
|
|
7
|
+
jetbrains_plugin_server/to_xml.py,sha256=k-TAxtFOhA3MKJd45gRVoXE_Sle2F4HgTwFhKHCyy7I,1050
|
|
8
|
+
jetbrains_plugin_server/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
jetbrains_plugin_server/model/data_listing.py,sha256=dVGnqgz4RP-ZjSKLOOtsxeMKcAZH23mFnzDtXWQB-Vo,1396
|
|
10
|
+
jetbrains_plugin_server/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
jetbrains_plugin_server/tools/dl_data.py,sha256=e-TqKTxQxcDZkdDIFGJs1eprbNoJ_Z44pxHNLMjFDz8,2286
|
|
12
|
+
jetbrains_plugin_server/tools/gen_json_cache.py,sha256=UvRQ3R6TEpb-g2fCZLqd1RMKSNvCCuKg_s0wfpQUD7s,2770
|
|
13
|
+
jetbrains_plugin_server-0.0.1.dist-info/licenses/LICENSE.md,sha256=tAj5NBpLsYCAvvYJNxPPffRCtXvdbDEihvwpVFdB_rw,1064
|
|
14
|
+
jetbrains_plugin_server-0.0.1.dist-info/METADATA,sha256=Tu7dce-Ms1fqYG9JLIvBmMMnpaunQryoEEpyEEtCAXc,1542
|
|
15
|
+
jetbrains_plugin_server-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
jetbrains_plugin_server-0.0.1.dist-info/top_level.txt,sha256=r7ESDf8AgP-KTE2kmXknIAY3bf_BPQ-YohWCZO4wKpo,24
|
|
17
|
+
jetbrains_plugin_server-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 azro352
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
jetbrains_plugin_server
|