Lots of work
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.chinook/
|
.chinook/
|
||||||
.environ/
|
.environ/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
.vscode/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -1,13 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [0.0.1] - <DATE>
|
## [0.0.1] - <DATE>
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
### Changed
|
### Changed
|
||||||
### Fixed
|
### Fixed
|
||||||
### Removed
|
### Removed
|
||||||
|
|||||||
14
LICENSE.md
14
LICENSE.md
@@ -1,7 +1,7 @@
|
|||||||
Copyright 2026 John Christman
|
Copyright 2026 John Christman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from ._logger import logger
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
import logging
|
import yaml
|
||||||
|
|
||||||
from chinook import pipeline
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
from argparse import Namespace
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from semver import Version
|
from semver import Version
|
||||||
|
|
||||||
|
|
||||||
|
# Load application configurations.
|
||||||
|
cfgdir = Path.home() / ".config" / "chinook" / "remotes.yaml"
|
||||||
|
remotes = yaml.full_load(cfgdir) if Path.exists(cfgdir) else []
|
||||||
|
|
||||||
|
|
||||||
|
def _build(args: Namespace) -> None:
|
||||||
|
from chinook import management
|
||||||
|
from chinook import pipeline
|
||||||
|
|
||||||
|
from chinook._logger import logger
|
||||||
|
from chinook.models import Destination
|
||||||
|
from chinook.models import Origination
|
||||||
|
|
||||||
|
try:
|
||||||
|
projpath = Path(args.project)
|
||||||
|
projcfg = management.load(projpath)
|
||||||
|
if projcfg != None:
|
||||||
|
root = projpath.parent
|
||||||
|
projcfg.origination = Origination(root)
|
||||||
|
projcfg.destination = Destination(root)
|
||||||
|
return pipeline.build(projcfg)
|
||||||
|
except Exception as err:
|
||||||
|
logger.exception(str(err))
|
||||||
|
logger.critical("Failed to build project")
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
|
|
||||||
console = logging.StreamHandler()
|
|
||||||
console.setLevel(logging.DEBUG)
|
|
||||||
console.setFormatter(formatter)
|
|
||||||
|
|
||||||
logger = logging.getLogger("chinook")
|
|
||||||
logger.addHandler(console)
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
# Parent parser to all subcommands.
|
# Parent parser to all subcommands.
|
||||||
parser = ArgumentParser(
|
parser = ArgumentParser(
|
||||||
prog = "chinook",
|
prog = "chinook",
|
||||||
@@ -24,12 +41,12 @@ def main() -> None:
|
|||||||
|
|
||||||
commands = parser.add_subparsers(required=True)
|
commands = parser.add_subparsers(required=True)
|
||||||
buildcmd = commands.add_parser("build",help="Builds your Chinook project")
|
buildcmd = commands.add_parser("build",help="Builds your Chinook project")
|
||||||
buildcmd.set_defaults(func=pipeline.build)
|
buildcmd.set_defaults(func=_build)
|
||||||
buildcmd.add_argument(
|
buildcmd.add_argument(
|
||||||
"project",
|
"project",
|
||||||
nargs="?",
|
nargs="?",
|
||||||
default=".",
|
default=".",
|
||||||
type=Path,
|
type=str,
|
||||||
help="The path to the project to build",
|
help="The path to the project to build",
|
||||||
metavar="PROJECT"
|
metavar="PROJECT"
|
||||||
)
|
)
|
||||||
|
|||||||
3
chinook/_config.py
Normal file
3
chinook/_config.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
config = None
|
||||||
10
chinook/_logger.py
Normal file
10
chinook/_logger.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
_formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
|
||||||
|
_console = logging.StreamHandler()
|
||||||
|
_console.setLevel(logging.DEBUG)
|
||||||
|
_console.setFormatter(_formatter)
|
||||||
|
|
||||||
|
logger = logging.getLogger("chinook")
|
||||||
|
logger.addHandler(_console)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
6
chinook/compiler/gcc.py
Normal file
6
chinook/compiler/gcc.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from ..models import Project
|
||||||
|
from ..models import Target
|
||||||
|
|
||||||
|
|
||||||
|
def compile(target: Target, project: Project) -> None:
|
||||||
|
...
|
||||||
6
chinook/management/__init__.py
Normal file
6
chinook/management/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from ._except import NoProjectFoundError
|
||||||
|
from ._except import NoPackageFoundError
|
||||||
|
from ._except import NoRemotesFoundError
|
||||||
|
from ._load import load
|
||||||
|
from ._shared import projects
|
||||||
|
from ._shared import targets
|
||||||
30
chinook/management/_except.py
Normal file
30
chinook/management/_except.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from ..models import Project
|
||||||
|
|
||||||
|
class NoProjectFoundError(Exception):
|
||||||
|
@property
|
||||||
|
def path(self) -> Path:
|
||||||
|
return self._path
|
||||||
|
|
||||||
|
def __init__(self, path: Path) -> None:
|
||||||
|
super().__init__(f"Project could not be found: {path}")
|
||||||
|
self._path = path
|
||||||
|
|
||||||
|
class NoPackageFoundError(Exception):
|
||||||
|
@property
|
||||||
|
def path(self) -> Path:
|
||||||
|
return self._path
|
||||||
|
|
||||||
|
def __init__(self, path: Path) -> None:
|
||||||
|
super().__init__(f"Package could not be found: {path}")
|
||||||
|
self._path = path
|
||||||
|
|
||||||
|
class NoRemotesFoundError(Exception):
|
||||||
|
@property
|
||||||
|
def project(self) -> Project:
|
||||||
|
return self._project
|
||||||
|
|
||||||
|
def __init__(self, project: Project) -> None:
|
||||||
|
super().__init__(f"Project remotes not present: {project.cid}")
|
||||||
|
self._project = project
|
||||||
|
|
||||||
77
chinook/management/_load.py
Normal file
77
chinook/management/_load.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from ..models import Project
|
||||||
|
from ..remote import clone
|
||||||
|
from ..remote import RemoteDomainUnavailableError
|
||||||
|
from ..remote import RemoteAddressNonexistentError
|
||||||
|
from ..remote import PackageCloneFailedError
|
||||||
|
from .._config import config
|
||||||
|
from .._logger import logger
|
||||||
|
from ._except import NoProjectFoundError
|
||||||
|
from ._except import NoPackageFoundError
|
||||||
|
from ._except import NoRemotesFoundError
|
||||||
|
from ._shared import projects
|
||||||
|
from ._shared import targets
|
||||||
|
|
||||||
|
|
||||||
|
def load(path: Path) -> Project:
|
||||||
|
if path in projects:
|
||||||
|
return projects[path]
|
||||||
|
|
||||||
|
fullpath = path / "chinookfile"
|
||||||
|
if not Path.exists(fullpath):
|
||||||
|
raise NoProjectFoundError(fullpath)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(fullpath, 'r') as file:
|
||||||
|
project = yaml.full_load(file.read())
|
||||||
|
# projects[path] = config
|
||||||
|
_load_packages(project)
|
||||||
|
_collect_targets(project)
|
||||||
|
return project
|
||||||
|
except Exception as rethrowme:
|
||||||
|
raise rethrowme
|
||||||
|
|
||||||
|
|
||||||
|
def _load_packages(project: Project) -> None:
|
||||||
|
# Don't process packages if none are present.
|
||||||
|
if not hasattr(project, "packages"):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Packages present, but no remotes is not good :(
|
||||||
|
if len(project.packages) != 0 and \
|
||||||
|
len(config.remotes) == 0:
|
||||||
|
raise NoRemotesFoundError(project)
|
||||||
|
|
||||||
|
for pckg in project.packages:
|
||||||
|
try:
|
||||||
|
# Get available versions, find highest possible version supported.
|
||||||
|
|
||||||
|
path = pckg.diskpath
|
||||||
|
if not Path.exists(path):
|
||||||
|
clone(config.remotes, pckg, path)
|
||||||
|
load(path)
|
||||||
|
except RemoteDomainUnavailableError as err:
|
||||||
|
# We tried to ping the remote to make sure we could download from it, and
|
||||||
|
# we got no response from the remote.
|
||||||
|
logger.warning(str(err))
|
||||||
|
except RemoteAddressNonexistentError as err:
|
||||||
|
# We checked if the remote address existed and we found that it did not.
|
||||||
|
logger.warning(str(err))
|
||||||
|
except PackageCloneFailedError as err:
|
||||||
|
# Remotes and pacakge exist, clone was uncessuccessful.
|
||||||
|
# Either clone command failed, or path did not exist afterwards.
|
||||||
|
logger.error(str(err))
|
||||||
|
except NoProjectFoundError as err:
|
||||||
|
# Remotes and package exist, clone was successful, but chinookfile is not
|
||||||
|
# present in the package directory.
|
||||||
|
raise NoPackageFoundError(err.project)
|
||||||
|
except Exception as rethrowme:
|
||||||
|
raise rethrowme
|
||||||
|
|
||||||
|
def _collect_targets(project: Project) -> None:
|
||||||
|
for target in project.targets:
|
||||||
|
name = f"{project.cid}#{target.name}"
|
||||||
|
if name not in targets:
|
||||||
|
targets[name] = target
|
||||||
7
chinook/management/_shared.py
Normal file
7
chinook/management/_shared.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from ..models import Package
|
||||||
|
from ..models import Project
|
||||||
|
from ..models import Target
|
||||||
|
|
||||||
|
packages: dict[str, Package] = {}
|
||||||
|
projects: dict[str, Project] = {}
|
||||||
|
targets: dict[str, Target] = {}
|
||||||
@@ -1 +1,13 @@
|
|||||||
from ._chinookfile import ChinookFile
|
from ._accessor import Accessor
|
||||||
|
from ._accessor import PublicAccessor
|
||||||
|
from ._accessor import ProtectedAccessor
|
||||||
|
from ._accessor import PrivateAccessor
|
||||||
|
from ._branch import Branch
|
||||||
|
from ._destination import Destination
|
||||||
|
from ._identity import Identity
|
||||||
|
from ._level import Level
|
||||||
|
from ._origination import Origination
|
||||||
|
from ._output import Output
|
||||||
|
from ._project import Project
|
||||||
|
from ._package import Package
|
||||||
|
from ._target import Target
|
||||||
|
|||||||
63
chinook/models/_accessor.py
Normal file
63
chinook/models/_accessor.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ._level import Level
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Accessor:
|
||||||
|
level: Level
|
||||||
|
value: str
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return hash((self.level, self.value))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_list(value: Optional[list]) -> list['Accessor']:
|
||||||
|
return [Accessor.from_value(v) for v in value] if value != None else []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_value(value: dict | str) -> 'Accessor':
|
||||||
|
if isinstance(value, str):
|
||||||
|
return Accessor(level = Level.PUBLIC, value = value)
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return Accessor(**dict)
|
||||||
|
if isinstance(value, Accessor):
|
||||||
|
return value
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
class PublicAccessor(yaml.YAMLObject, Accessor):
|
||||||
|
yaml_tag = u"!public"
|
||||||
|
def __init__(self, value: str) -> None:
|
||||||
|
super().__init__(level = Level.PUBLIC, value = value)
|
||||||
|
|
||||||
|
class ProtectedAccessor(yaml.YAMLObject, Accessor):
|
||||||
|
yaml_tag = u"!protected"
|
||||||
|
def __init__(self, value: str) -> None:
|
||||||
|
super().__init__(level = Level.PROTECTED, value = value)
|
||||||
|
|
||||||
|
class PrivateAccessor(yaml.YAMLObject, Accessor):
|
||||||
|
yaml_tag = u"!private"
|
||||||
|
def __init__(self, value: str) -> None:
|
||||||
|
super().__init__(level = Level.PRIVATE, value = value)
|
||||||
|
|
||||||
|
|
||||||
|
yaml.add_constructor(
|
||||||
|
PublicAccessor.yaml_tag,
|
||||||
|
lambda loader, node:
|
||||||
|
PublicAccessor(loader.construct_scalar(node))
|
||||||
|
)
|
||||||
|
|
||||||
|
yaml.add_constructor(
|
||||||
|
ProtectedAccessor.yaml_tag,
|
||||||
|
lambda loader, node:
|
||||||
|
ProtectedAccessor(loader.construct_scalar(node))
|
||||||
|
)
|
||||||
|
|
||||||
|
yaml.add_constructor(
|
||||||
|
PrivateAccessor.yaml_tag,
|
||||||
|
lambda loader, node:
|
||||||
|
PrivateAccessor(loader.construct_scalar(node))
|
||||||
|
)
|
||||||
6
chinook/models/_activation.py
Normal file
6
chinook/models/_activation.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Activation(yaml.YAMLObject):
|
||||||
|
pass
|
||||||
34
chinook/models/_branch.py
Normal file
34
chinook/models/_branch.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from dataclasses import field
|
||||||
|
|
||||||
|
from semantic_version import Version
|
||||||
|
from semantic_version import NpmSpec
|
||||||
|
from semantic_version import validate
|
||||||
|
|
||||||
|
from typing import ClassVar
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Branch(yaml.YAMLObject):
|
||||||
|
yaml_tag: ClassVar[str] = u"!branch"
|
||||||
|
|
||||||
|
value: str
|
||||||
|
_valid: Optional[bool] = field(init=False,default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_version(self) -> Version:
|
||||||
|
if not self.is_version:
|
||||||
|
return Version(0, 0, 0, self.value)
|
||||||
|
return Version.parse(self.value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_version(self) -> bool:
|
||||||
|
if self._valid == None:
|
||||||
|
self._valid = validate(self.value)
|
||||||
|
return self._valid
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.value
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ChinookFile:
|
|
||||||
pass
|
|
||||||
53
chinook/models/_destination.py
Normal file
53
chinook/models/_destination.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Support custom output file extension based on user
|
||||||
|
# or platform specification.
|
||||||
|
class Destination:
|
||||||
|
@property
|
||||||
|
def root(self) -> Path:
|
||||||
|
return self._root
|
||||||
|
|
||||||
|
@property
|
||||||
|
def binpath(self) -> Path:
|
||||||
|
return self._binpath
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dllpath(self) -> Path:
|
||||||
|
return self._binpath
|
||||||
|
|
||||||
|
@property
|
||||||
|
def libpath(self) -> Path:
|
||||||
|
return self._libpath
|
||||||
|
|
||||||
|
@property
|
||||||
|
def objpath(self) -> Path:
|
||||||
|
return self._objpath
|
||||||
|
|
||||||
|
def __init__(self, outpath: Path, mkdirs=True) -> None:
|
||||||
|
self._root = outpath / ".chinook"
|
||||||
|
self._binpath = self._root / "bin"
|
||||||
|
self._libpath = self._root / "lib"
|
||||||
|
self._objpath = self._root / "obj"
|
||||||
|
|
||||||
|
if mkdirs:
|
||||||
|
self._root.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._binpath.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._libpath.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._objpath.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cwd() -> 'Destination':
|
||||||
|
return Destination(Path.cwd(), mkdirs=False)
|
||||||
|
|
||||||
|
def bin(self, file: str) -> Path:
|
||||||
|
return self.binpath / file
|
||||||
|
|
||||||
|
def dll(self, file: str) -> Path:
|
||||||
|
return self.dllpath / f"{file}.so"
|
||||||
|
|
||||||
|
def lib(self, file: str) -> Path:
|
||||||
|
return self.libpath / f"lib{file}.a"
|
||||||
|
|
||||||
|
def obj(self, file: Path) -> Path:
|
||||||
|
return self.objpath / f"{file}.o"
|
||||||
36
chinook/models/_identity.py
Normal file
36
chinook/models/_identity.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import re
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from ._branch import Branch
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Identity(yaml.YAMLObject):
|
||||||
|
name: str
|
||||||
|
gpid: str
|
||||||
|
semv: Branch
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cid(self) -> str:
|
||||||
|
return f"{self.gpid}/{self.name}@{self.semv}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_cid(cid: str) -> dict[str, str]:
|
||||||
|
pattern = r"^(?P<gpid>[^/]+)/(?P<name>[^@]+)@(?P<semv>.+)$"
|
||||||
|
match = re.match(pattern, cid)
|
||||||
|
return match.groupdict() if match else {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_fields(fields: dict) -> 'Identity':
|
||||||
|
if name:=fields.get("name") == None:
|
||||||
|
raise AttributeError(name="name",obj=fields)
|
||||||
|
if gpid:=fields.get("gpid") == None:
|
||||||
|
raise AttributeError(name="gpid",obj=fields)
|
||||||
|
if semv:=fields.get("semv") == None:
|
||||||
|
raise AttributeError(name="semv",obj=fields)
|
||||||
|
return Identity(
|
||||||
|
name=name,
|
||||||
|
gpid=gpid,
|
||||||
|
semv=Branch(semv)
|
||||||
|
)
|
||||||
8
chinook/models/_level.py
Normal file
8
chinook/models/_level.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
|
||||||
|
class Level(IntEnum):
|
||||||
|
PUBLIC = auto()
|
||||||
|
PROTECTED = auto()
|
||||||
|
PRIVATE = auto()
|
||||||
19
chinook/models/_origination.py
Normal file
19
chinook/models/_origination.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class Origination:
|
||||||
|
@property
|
||||||
|
def root(self) -> Path:
|
||||||
|
return self._root
|
||||||
|
|
||||||
|
def __init__(self, inpath: Path) -> None:
|
||||||
|
self._root = inpath
|
||||||
|
self._srcpath = self._root / "source"
|
||||||
|
self._incpath = self._root / "include"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cwd() -> 'Origination':
|
||||||
|
return Origination(Path.cwd())
|
||||||
|
|
||||||
|
def src(self, file: Path) -> Path:
|
||||||
|
return self._root / file
|
||||||
9
chinook/models/_output.py
Normal file
9
chinook/models/_output.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
|
||||||
|
class Output(StrEnum):
|
||||||
|
EXE = "executable"
|
||||||
|
LIB = "archive"
|
||||||
|
DLL = "dynlib"
|
||||||
|
OBJ = "objfile"
|
||||||
|
INT = "interface"
|
||||||
59
chinook/models/_package.py
Normal file
59
chinook/models/_package.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from dataclasses import field
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from semantic_version import NpmSpec
|
||||||
|
|
||||||
|
from typing import ClassVar
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ._identity import Identity
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Package(yaml.YAMLObject):
|
||||||
|
yaml_tag: ClassVar[str] = u"!package"
|
||||||
|
|
||||||
|
name: str
|
||||||
|
gpid: str
|
||||||
|
spec: NpmSpec
|
||||||
|
tag: Optional[str] = field(init=False,default=None)
|
||||||
|
domain: Optional[str] = field(init=False,default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reponame(self) -> str:
|
||||||
|
return f"{self.gpid}/{self.name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def chinookid(self) -> str:
|
||||||
|
if self.tag == None:
|
||||||
|
raise ValueError
|
||||||
|
return f"{self.reponame}@{self.tag}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def remote(self) -> str:
|
||||||
|
if self.domain == None:
|
||||||
|
raise ValueError
|
||||||
|
return f"https://{self.domain}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def repository(self) -> str:
|
||||||
|
return f"{self.remote}/{self.reponame}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dirname(self) -> Path:
|
||||||
|
return self.chinookid
|
||||||
|
|
||||||
|
@property
|
||||||
|
def diskpath(self) -> Path:
|
||||||
|
return Path.home() / ".chinook" / self.chinookid
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_list(items: list) -> list['Package']:
|
||||||
|
return [Package.from_cid(item) for item in items]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_chinookid(cid: str) -> 'Package':
|
||||||
|
return Package(**Identity.from_cpid(cid))
|
||||||
13
chinook/models/_profile.py
Normal file
13
chinook/models/_profile.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Profile(yaml.YAMLObject):
|
||||||
|
yaml_tag: ClassVar[str] = u"!profile"
|
||||||
|
|
||||||
|
name: str
|
||||||
|
when: Optional[Triple]
|
||||||
30
chinook/models/_project.py
Normal file
30
chinook/models/_project.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from dataclasses import field
|
||||||
|
from typing import ClassVar
|
||||||
|
from ._identity import Identity
|
||||||
|
from ._package import Package
|
||||||
|
from ._target import Target
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Project(Identity):
|
||||||
|
yaml_tag: ClassVar[str] = u"!project"
|
||||||
|
|
||||||
|
packages: list[Package] = field(default_factory=list)
|
||||||
|
targets: list[Target] = field(default_factory=list)
|
||||||
|
options: dict[str, str] = field(default_factory=dict)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_fields(fields: dict) -> 'Project':
|
||||||
|
identity = Identity.from_fields(fields)
|
||||||
|
packages = fields.get("packages") or []
|
||||||
|
if targets:=fields.get("targets") == None:
|
||||||
|
raise AttributeError(name="targets", obj=fields)
|
||||||
|
return Project(
|
||||||
|
name = identity.name,
|
||||||
|
gpid = identity.gpid,
|
||||||
|
semv = identity.semv,
|
||||||
|
packages = [Package.from_fields(item) for item in packages],
|
||||||
|
targets = [Target.from_fields(item) for item in targets],
|
||||||
|
options = {}
|
||||||
|
)
|
||||||
29
chinook/models/_target.py
Normal file
29
chinook/models/_target.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from dataclasses import field
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
from ._accessor import Accessor
|
||||||
|
from ._output import Output
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Target(yaml.YAMLObject):
|
||||||
|
yaml_tag: ClassVar[str] = u"!target"
|
||||||
|
|
||||||
|
name: str
|
||||||
|
type: Output
|
||||||
|
options: set[Accessor]
|
||||||
|
sources: set[Accessor]
|
||||||
|
inherits: set[Accessor]
|
||||||
|
|
||||||
|
archives: set[Accessor] = field(default=set)
|
||||||
|
dynlibs: set[Accessor] = field(default=set)
|
||||||
|
|
||||||
|
def consolidate(self, parent: 'Target') -> None:
|
||||||
|
# NOTE: Do not need to append parents of parent.
|
||||||
|
self.options.update(parent.options)
|
||||||
|
self.sources.update(parent.sources)
|
||||||
|
self.archives.update(parent.archives)
|
||||||
|
self.dynlibs.update(parent.dynlibs)
|
||||||
19
chinook/models/_toolchain.py
Normal file
19
chinook/models/_toolchain.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
from ._triple import Triple
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Toolchain(yaml.YAMLObject):
|
||||||
|
yaml_tag: ClassVar[str] = u"!toolchain"
|
||||||
|
|
||||||
|
name: str
|
||||||
|
when: list[Triple]
|
||||||
|
compiler: Path
|
||||||
|
linker: Path
|
||||||
|
archiver: Path
|
||||||
|
debugger: Path
|
||||||
16
chinook/models/_triple.py
Normal file
16
chinook/models/_triple.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
from ._activation import Activation
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Triple(Activation):
|
||||||
|
yaml_tag: ClassVar[str] = u"!triple"
|
||||||
|
|
||||||
|
arch: str
|
||||||
|
vend: str
|
||||||
|
sys: str
|
||||||
|
abi: str
|
||||||
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
from ._build import build
|
from ._build import build
|
||||||
|
|
||||||
__all__ = [ build ]
|
|
||||||
|
|||||||
@@ -1,25 +1,11 @@
|
|||||||
from ..models import ChinookFile
|
from ..models import Project
|
||||||
|
from .._logger import logger
|
||||||
|
from ._compile import compile
|
||||||
|
from ._except import NoTargetsFoundError
|
||||||
|
|
||||||
from pathlib import Path
|
def build(project: Project) -> None:
|
||||||
from typing import overload
|
# TODO: Download, catalog, and build dependencies
|
||||||
|
# TODO: Build the current configuration
|
||||||
|
if len(project.targets) == 0:
|
||||||
@overload
|
raise NoTargetsFoundError(project)
|
||||||
def build(path: Path) -> None: ...
|
logger.info(f"Building {project.cid}")
|
||||||
|
|
||||||
@overload
|
|
||||||
def build(file: ChinookFile) -> None: ...
|
|
||||||
|
|
||||||
|
|
||||||
def build(value) -> None:
|
|
||||||
if isinstance(value, Path):
|
|
||||||
return _build_from_path(value)
|
|
||||||
elif isinstance(value, ChinookFile):
|
|
||||||
return _build_from_file(value)
|
|
||||||
|
|
||||||
|
|
||||||
def _build_from_path(path: Path) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _build_from_file(file: ChinookFile) -> None:
|
|
||||||
pass
|
|
||||||
|
|||||||
4
chinook/pipeline/_compile.py
Normal file
4
chinook/pipeline/_compile.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from ..models import Target
|
||||||
|
|
||||||
|
def compile(target: Target) -> None:
|
||||||
|
...
|
||||||
2
chinook/pipeline/_except.py
Normal file
2
chinook/pipeline/_except.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
class NoTargetsFoundError(Exception):
|
||||||
|
pass
|
||||||
1
chinook/pipeline/_shared.py
Normal file
1
chinook/pipeline/_shared.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
6
chinook/remote/__init__.py
Normal file
6
chinook/remote/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from ._clone import clone
|
||||||
|
from ._exists import exists
|
||||||
|
from ._except import RemoteDomainUnavailableError
|
||||||
|
from ._except import RemoteAddressNonexistentError
|
||||||
|
from ._except import PackageCloneFailedError
|
||||||
|
from ._ping import ping
|
||||||
63
chinook/remote/_clone.py
Normal file
63
chinook/remote/_clone.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import overload
|
||||||
|
from ..models import Package
|
||||||
|
from ..shell import execute
|
||||||
|
from ._except import RemoteDomainUnavailableError
|
||||||
|
from ._except import RemoteAddressNonexistentError
|
||||||
|
from ._except import PackageCloneFailedError
|
||||||
|
from ._exists import exists
|
||||||
|
from ._ping import ping
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def clone(
|
||||||
|
domains: list[str],
|
||||||
|
fspath: Path,
|
||||||
|
package: Package
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def clone(
|
||||||
|
domain: str,
|
||||||
|
fspath: Path,
|
||||||
|
pacakge: Package
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
def clone(
|
||||||
|
domain: str | list[str],
|
||||||
|
fspath: Path,
|
||||||
|
package: Package
|
||||||
|
) -> None:
|
||||||
|
if package.remote != None:
|
||||||
|
return _clone_from_domain(package.remote, fspath, package)
|
||||||
|
|
||||||
|
if isinstance(domain, str):
|
||||||
|
return _clone_from_domain(domain, fspath, package)
|
||||||
|
|
||||||
|
|
||||||
|
def _clone_from_domain(package: Package) -> None:
|
||||||
|
if package.tag == None:
|
||||||
|
raise ValueError("No valid tag for package.")
|
||||||
|
|
||||||
|
cloned = True
|
||||||
|
cmdstr = "git clone --branch {} {} {}"
|
||||||
|
def _handle_error(_: Exception) -> None:
|
||||||
|
nonlocal cloned
|
||||||
|
cloned = False
|
||||||
|
|
||||||
|
if not ping(package.remote):
|
||||||
|
raise RemoteDomainUnavailableError(package.remote)
|
||||||
|
|
||||||
|
if not exists(package.repository):
|
||||||
|
raise RemoteAddressNonexistentError(package.repository)
|
||||||
|
|
||||||
|
cmd = cmdstr.format(
|
||||||
|
package.tag,
|
||||||
|
package.repository,
|
||||||
|
package.diskpath
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(command = cmd, on_error = _handle_error)
|
||||||
|
if not cloned or not Path.exists(package.diskpath):
|
||||||
|
raise PackageCloneFailedError(package.cid)
|
||||||
11
chinook/remote/_except.py
Normal file
11
chinook/remote/_except.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
class RemoteDomainUnavailableError(Exception):
|
||||||
|
def __init__(self, domain: str) -> None:
|
||||||
|
super().__init__(f"Domain is unavailable: {domain}")
|
||||||
|
|
||||||
|
class RemoteAddressNonexistentError(Exception):
|
||||||
|
def __init__(self, address: str) -> None:
|
||||||
|
super().__init__(f"Address does not exist: {address}")
|
||||||
|
|
||||||
|
class PackageCloneFailedError(Exception):
|
||||||
|
def __init__(self, pckgid: str) -> None:
|
||||||
|
super().__init__(f"Failed to clone package: {pckgid}")
|
||||||
11
chinook/remote/_exists.py
Normal file
11
chinook/remote/_exists.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from ..shell import execute
|
||||||
|
|
||||||
|
|
||||||
|
def exists(addr: str) -> bool:
|
||||||
|
repo_exists = True
|
||||||
|
command_str = "git ls-remote --exit-code -h {}"
|
||||||
|
def _handle_error(error: Exception) -> None:
|
||||||
|
nonlocal repo_exists
|
||||||
|
repo_exists = False
|
||||||
|
execute(command_str.format(addr), _handle_error)
|
||||||
|
return repo_exists
|
||||||
11
chinook/remote/_ping.py
Normal file
11
chinook/remote/_ping.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from ..shell import execute
|
||||||
|
|
||||||
|
|
||||||
|
def ping(addr: str) -> bool:
|
||||||
|
can_ping = True
|
||||||
|
cmd_str = "ping {} -W 1"
|
||||||
|
def _handle_error(error: Exception) -> None:
|
||||||
|
nonlocal can_ping
|
||||||
|
can_ping = False
|
||||||
|
execute(cmd_str.format(addr), _handle_error)
|
||||||
|
return can_ping
|
||||||
1
chinook/shell/__init__.py
Normal file
1
chinook/shell/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from ._execute import execute
|
||||||
29
chinook/shell/_execute.py
Normal file
29
chinook/shell/_execute.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from subprocess import CalledProcessError
|
||||||
|
from subprocess import PIPE
|
||||||
|
from subprocess import run
|
||||||
|
|
||||||
|
from typing import Callable
|
||||||
|
from typing import Optional
|
||||||
|
DataCallback = Callable[[str, str, str], None]
|
||||||
|
ErrorCallback = Callable[[Exception], None]
|
||||||
|
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
command: str,
|
||||||
|
on_data: Optional[DataCallback],
|
||||||
|
on_error: Optional[ErrorCallback]
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
result = run(
|
||||||
|
command,
|
||||||
|
shell = True,
|
||||||
|
check = True,
|
||||||
|
stdout = PIPE,
|
||||||
|
stderr = PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
if on_data != None:
|
||||||
|
on_data(command, result.stdout, result.stderr)
|
||||||
|
except CalledProcessError as error:
|
||||||
|
if on_error != None:
|
||||||
|
on_error(error)
|
||||||
5
chinook/triple/__init__.py
Normal file
5
chinook/triple/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ._arch import Architecture
|
||||||
|
from ._environ import Environment
|
||||||
|
from ._system import System
|
||||||
|
from ._system import SystemData
|
||||||
|
from ._vendor import Vendor
|
||||||
49
chinook/triple/_arch.py
Normal file
49
chinook/triple/_arch.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from enum import auto
|
||||||
|
from enum import unique
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ArchDataMixin:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Architecture(Enum):
|
||||||
|
UNKNOWN = auto()
|
||||||
|
ARM = None # CUSTOM
|
||||||
|
AMDGCN = auto()
|
||||||
|
AARCH64 = None # CUSTOM
|
||||||
|
ASMJS = auto()
|
||||||
|
AVR = auto()
|
||||||
|
BPFEB = auto()
|
||||||
|
BPFEL = auto()
|
||||||
|
HEXAGON = auto()
|
||||||
|
X86_32 = None # CUSTOM
|
||||||
|
M68K = auto()
|
||||||
|
LOONGARCH64 = auto()
|
||||||
|
MIPS32 = None # CUSTOM
|
||||||
|
MIPS64 = None # CUSTOM
|
||||||
|
MSP430 = auto()
|
||||||
|
NVPTX64 = auto()
|
||||||
|
PULLEY32 = auto()
|
||||||
|
PULLEY64 = auto()
|
||||||
|
PULLEY32BE = auto()
|
||||||
|
PULLEY64BE = auto()
|
||||||
|
POWERPC = auto()
|
||||||
|
POWERPC64LE = auto()
|
||||||
|
RISCV32 = None # CUSTOM
|
||||||
|
RISCV64 = None # CUSTOM
|
||||||
|
S390X = auto()
|
||||||
|
SPARC = auto()
|
||||||
|
SPARC64 = auto()
|
||||||
|
SPARCV9 = auto()
|
||||||
|
WASM32 = auto()
|
||||||
|
WASM64 = auto()
|
||||||
|
X86_64 = auto()
|
||||||
|
X86_64H = auto()
|
||||||
|
XTENSA = auto()
|
||||||
|
CLEVER = None # CUSTOM
|
||||||
|
ZKASM = auto()
|
||||||
|
Z80 = None # CUSTOM
|
||||||
39
chinook/triple/_environ.py
Normal file
39
chinook/triple/_environ.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from enum import StrEnum
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
|
||||||
|
class Environment(StrEnum):
|
||||||
|
UNKNOWN = auto()
|
||||||
|
AMDGIZ = auto()
|
||||||
|
ANDROID = auto()
|
||||||
|
ANDROIDEABI = auto()
|
||||||
|
EABI = auto()
|
||||||
|
EABIHF = auto()
|
||||||
|
GNU = auto()
|
||||||
|
GNUABI64 = auto()
|
||||||
|
GNUEABI = auto()
|
||||||
|
GNUSPE = auto()
|
||||||
|
GNUX32 = auto()
|
||||||
|
GNU_ILP32 = auto()
|
||||||
|
GNULLVM = auto()
|
||||||
|
HERMITKERNEL = auto()
|
||||||
|
HURDKERNEL = auto()
|
||||||
|
LINUXKERNEL = auto()
|
||||||
|
MACABI = auto()
|
||||||
|
MUSL = auto()
|
||||||
|
MUSLEABI = auto()
|
||||||
|
MUSLEABIHF = auto()
|
||||||
|
MUSLABI64 = auto()
|
||||||
|
MSVC = auto()
|
||||||
|
NEWLIB = auto()
|
||||||
|
NONE = auto()
|
||||||
|
KERNEL = auto()
|
||||||
|
UCLIBC = auto()
|
||||||
|
UCLIBCEABI = auto()
|
||||||
|
UCLIBCEABIHF = auto()
|
||||||
|
SGX = auto()
|
||||||
|
SIM = auto()
|
||||||
|
SOFTFLOAT = auto()
|
||||||
|
SPE = auto()
|
||||||
|
THREADS = auto()
|
||||||
|
OHOS = auto()
|
||||||
66
chinook/triple/_system.py
Normal file
66
chinook/triple/_system.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from enum import auto
|
||||||
|
from semver import Version
|
||||||
|
from typing import Any
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SystemData:
|
||||||
|
name: str
|
||||||
|
semv: Optional[Version]
|
||||||
|
|
||||||
|
|
||||||
|
class _SystemDataMixin(Enum):
|
||||||
|
@staticmethod
|
||||||
|
def _generate_next_value_(
|
||||||
|
name: str,
|
||||||
|
start: int,
|
||||||
|
count: int,
|
||||||
|
prevs: list[Any]
|
||||||
|
) -> SystemData:
|
||||||
|
return SystemData(name, None)
|
||||||
|
|
||||||
|
|
||||||
|
class System(_SystemDataMixin):
|
||||||
|
UNKNOWN = auto()
|
||||||
|
AIX = auto()
|
||||||
|
AMDHSA = auto()
|
||||||
|
BITRIG = auto()
|
||||||
|
CLOUDABI = auto()
|
||||||
|
CUDA = auto()
|
||||||
|
CYGWIN = auto()
|
||||||
|
DARWIN = auto()
|
||||||
|
DRAGONFLY = auto()
|
||||||
|
EMSCRIPTEN = auto()
|
||||||
|
ESPIDF = auto()
|
||||||
|
FREEBSD = auto()
|
||||||
|
FUCHSIA = auto()
|
||||||
|
HAIKU = auto()
|
||||||
|
HERMIT = auto()
|
||||||
|
HORIZON = auto()
|
||||||
|
HURD = auto()
|
||||||
|
ILLUMOS = auto()
|
||||||
|
IOS = auto()
|
||||||
|
L4RE = auto()
|
||||||
|
LINUX = auto()
|
||||||
|
MACOSX = auto()
|
||||||
|
NEBULET = auto()
|
||||||
|
NETBSD = auto()
|
||||||
|
NONE = auto()
|
||||||
|
OPENBSD = auto()
|
||||||
|
PSP = auto()
|
||||||
|
REDOX = auto()
|
||||||
|
SOLARIS = auto()
|
||||||
|
SOLIDASP3 = auto()
|
||||||
|
TVOS = auto()
|
||||||
|
UEFI = auto()
|
||||||
|
VISIONOS = auto()
|
||||||
|
VXWORKS = auto()
|
||||||
|
WASI = auto()
|
||||||
|
WASIP1 = auto()
|
||||||
|
WASIP2 = auto()
|
||||||
|
WATCHOS = auto()
|
||||||
|
WINDOWS = auto()
|
||||||
|
XROS = auto()
|
||||||
19
chinook/triple/_vendor.py
Normal file
19
chinook/triple/_vendor.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from enum import StrEnum
|
||||||
|
from enum import auto
|
||||||
|
|
||||||
|
|
||||||
|
class Vendor(StrEnum):
|
||||||
|
UNKNOWN = auto()
|
||||||
|
AMD = auto()
|
||||||
|
APPLE = auto()
|
||||||
|
ESPRESSIF = auto()
|
||||||
|
FORTANIX = auto()
|
||||||
|
IBM = auto()
|
||||||
|
KMC = auto()
|
||||||
|
NINTENDO = auto()
|
||||||
|
NVIDIA = auto()
|
||||||
|
PC = auto()
|
||||||
|
RUMPRUN = auto()
|
||||||
|
SUN = auto()
|
||||||
|
UWP = auto()
|
||||||
|
WRS = auto()
|
||||||
9
example/executable/chinookfile
Normal file
9
example/executable/chinookfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name: executable
|
||||||
|
gpid: examples
|
||||||
|
semv: 1.0.0
|
||||||
|
|
||||||
|
targets:
|
||||||
|
- name: example
|
||||||
|
type: executable
|
||||||
|
srcs:
|
||||||
|
- ./entry.cpp
|
||||||
11
example/executable/entry.cpp
Normal file
11
example/executable/entry.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#if __cplusplus >= 202302L
|
||||||
|
# define print(x) std::print(#x)
|
||||||
|
#else // Old C++ version.
|
||||||
|
# define print(x) std::cout << #x << std::endl
|
||||||
|
#endif // Check C++ version.
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print("Hello, World!");
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "chinook"
|
name = "chinook"
|
||||||
version = "1.0.0-alpha"
|
version = "1.0.0-alpha"
|
||||||
description = "Opinionated build tool for C/C++."
|
description = "Opinionated build tool for C/C++."
|
||||||
dependencies = ["PyYAML", "semver"]
|
dependencies = ["PyYAML", "semantic-version"]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
chinook = "chinook.__main__:main"
|
chinook = "chinook.__main__:main"
|
||||||
|
|||||||
Reference in New Issue
Block a user