Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pdm-python
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/workspaces/guibuilder/.venv/bin/python
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
5 changes: 4 additions & 1 deletion src/phoebus_guibuilder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
Version number as calculated by poetry-dynamic-versioning
"""

from phoebus_guibuilder.datatypes import Beamline, Component, Entry
from phoebus_guibuilder.guibuilder import Guibuilder

from ._version import __version__

__all__ = ["__version__"]
__all__ = ["__version__", "Beamline", "Component", "Entry", "Guibuilder"]
6 changes: 4 additions & 2 deletions src/phoebus_guibuilder/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from argparse import ArgumentParser
from collections.abc import Sequence

from . import __version__, guibuilder
from . import __version__
from .guibuilder import Guibuilder

__all__ = ["main"]

Expand All @@ -20,7 +21,8 @@ def main(args: Sequence[str] | None = None) -> None:
)
_args = parser.parse_args(args)

guibuilder.main(_args.filename)
gb = Guibuilder(_args.filename)
gb.extract_from_create_gui()


if __name__ == "__main__":
Expand Down
67 changes: 67 additions & 0 deletions src/phoebus_guibuilder/datatypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import re
from dataclasses import dataclass


@dataclass
class Beamline:
dom: str
desc: str


@dataclass
class Entry:
type: str
DESC: str | None
P: str
M: str | None
R: str | None


@dataclass
class Component:
name: str
desc: str
prefix: str
filename: str | None = None

def __post_init__(self):
self._extract_p_and_r()

def __repr__(self) -> str:
return f"Component(name={self.name}, desc={self.desc}, \
prefix={self.P}, suffix={self.R}, filename={self.filename})"

def _extract_p_and_r(self):
pattern = re.compile(
r"""
^ # start of string
(?= # lookahead to ensure the following pattern matches
[A-Za-z0-9-]{14,16} # match 14 to 16 alphanumeric characters or hyphens
[:A-Za-z0-9]* # match zero or more colons or alphanumeric characters
[.A-Za-z0-9] # match a dot or alphanumeric character
)
(?!.*--) # negative lookahead to ensure no double hyphens
(?!.*:\..) # negative lookahead to ensure no colon followed by a dot
( # start of capture group 1
(?:[A-Za-z0-9]{2,5}-){3} # match 2 to 5 alphanumeric characters followed
# by a hyphen, repeated 3 times
[\d]* # match zero or more digits
[^:]? # match zero or one non-colon character
)
(?::([a-zA-Z0-9:]*))? # match zero or one colon followed by zero or more
# alphanumeric characters or colons (capture group 2)
(?:\.([a-zA-Z0-9]+))? # match zero or one dot followed by one or more
# alphanumeric characters (capture group 3)
$ # end of string
""",
re.VERBOSE,
)

match = re.match(pattern, self.prefix)
if match:
self.P: str = match.group(1)
self.R: str = match.group(2)
# TODO: Is this needed?
self.attribute: str | None = match.group(3)
else:
raise AttributeError(f"No valid PV prefix found for {self.name}.")
119 changes: 119 additions & 0 deletions src/phoebus_guibuilder/git_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import base64
import re

import requests


class GitYaml:
def __init__(self, dom: str):
self.pattern: str = "^(.*)-(.*)-(.*)"
self.dom: str = dom
self.git_ref: str = (
f"https://api.github.com/repos/epics-containers/{dom}-services/git/refs"
)

def re_group(self, component: str) -> str | None:
match: re.Match[str] | None = re.match(self.pattern, component)

if match:
return match.group(1)

def get_json_from_url(self, url: str) -> dict | None:
try:
response = requests.get(url)
print(response)
response.raise_for_status()
if response:
return response.json()
except requests.exceptions.HTTPError as err:
print(err.response.text)
return err.response.json()

def get_yaml(self, url) -> str | None:
data: dict | None = self.get_json_from_url(url)
if data is not None:
base64_content = data["content"]
decoded_content = base64.b64decode(base64_content).decode("utf-8")

return decoded_content

def fetch_matches(
self,
tree: dict,
task: str,
prefix: str = "",
option: str = "",
) -> str | None:
if task == "ref":
matching_refs = [
item
for item in tree
if isinstance(item, dict) and item.get("ref") == "refs/heads/main"
]
return matching_refs[0]["object"]["sha"]
elif task == "services":
tree = tree["tree"]
matching_url = [
item
for item in tree
if isinstance(item, dict) and item.get("path") == "services"
]
print(f"DEBUG1:{matching_url}")
return matching_url[0]["url"]

elif task == "subfolder":
tree = tree["tree"]
matching_folders = [
item
for item in tree
if isinstance(item, dict)
and self.re_group(str(item.get("path"))) == prefix.lower()
]
if matching_folders:
return matching_folders[0]["url"]

elif task == "config":
tree = tree["tree"]
config = [
item
for item in tree
if isinstance(item, dict) and item.get("path") == "config"
]
return config[0]["url"]

else:
answer = [
item
for item in tree
if isinstance(item, dict) and item.get(option) == task
]
return answer[0]["url"]

def fetch_ioc_yaml(
self,
):
commit_hashes: dict | None = self.get_json_from_url(self.git_ref)

assert commit_hashes is not None, "Could not pull commit hashes"
if commit_hashes["message"]:
return

main_hash = self.fetch_matches(commit_hashes, "ref")
main_url = f"https://api.github.com/repos/epics-containers/{self.dom}-services/git/trees/{main_hash}"
main_tree: dict | None = self.get_json_from_url(main_url)
assert main_tree is not None, "Could not obtain main json tree"

services_url: str | None = self.fetch_matches(main_tree, "services")
assert services_url is not None, "Could not fetch services url"

services_json: dict | None = self.get_json_from_url(services_url)
assert services_json is not None, "Could not fetch services json tree"
config_url = self.fetch_matches(services_json, "subfolder")

if config_url is not None:
config_json: dict | None = self.get_json_from_url(config_url)
assert config_json is not None, "Could not fetch config json tree"

ioc_yaml_url = self.fetch_matches(config_json, "config")

return self.get_yaml(ioc_yaml_url)
Loading
Loading