Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvements #21

Merged
merged 6 commits into from
May 7, 2023
Merged
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
2 changes: 1 addition & 1 deletion local/variables/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
major: 1
minor: 2
minor: 3
patch: 0
entry: rcmpy
10 changes: 5 additions & 5 deletions rcmpy/commands/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ def apply_env(args: _Namespace, env: Environment) -> int:

result = 0

is_new = env.state.is_new()

for file in env.config.files:
# Check if a template is found for this file.
if file.template not in env.templates_by_name:
result += 1
env.logger.error("Template '%s' not found!", file.template)
continue

if not file.platform:
if not file.evaluate(env.env_data):
continue

is_new = env.state.is_new()

# Check if this file has any updated templates.
if args.force or is_new or env.is_updated(file):
if args.force or is_new or not file.present or env.is_updated(file):
template = env.templates_by_name[file.template]

# If a template doesn't require rendering, use it as-is.
Expand All @@ -44,7 +44,7 @@ def apply_env(args: _Namespace, env: Environment) -> int:
# Render the template to the build directory.
source = env.build.joinpath(file.template)
with source.open("w") as path_fd:
path_fd.write(template.template.render(env.state.configs))
path_fd.write(template.template.render(env.template_data))
env.logger.info("Rendered '%s'.", rel(source))

# Update the output file.
Expand Down
6 changes: 2 additions & 4 deletions rcmpy/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def init(self, data: _JsonObject) -> None:
Path(expandvars(file["directory"])).expanduser(),
file.get("name", file["template"]),
file["link"],
file["executable"],
file["condition"],
set(file.get("platforms", [])),
)

Expand All @@ -54,7 +56,3 @@ def init(self, data: _JsonObject) -> None:
self.templates.add(template)

self.files.append(new)

def asdict(self) -> _JsonObject:
"""Obtain a dictionary representing this instance."""
return self.data
25 changes: 24 additions & 1 deletion rcmpy/config/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@
from pathlib import Path
from shutil import copyfile
import sys
from typing import Set
from typing import Any, Dict, Set

# third-party
from vcorelib.logging import LoggerType
from vcorelib.paths import rel


def set_exec_flags(path: Path) -> None:
"""Set the executable bits, but respect the 'read' bits."""
mode = path.stat().st_mode
path.chmod(mode | ((mode & 0o444) >> 2))


@dataclass
class ManagedFile:
"""
Expand All @@ -28,6 +34,9 @@ class ManagedFile:
name: str

link: bool
executable: bool

condition: str

platforms: Set[str]

Expand All @@ -36,11 +45,22 @@ def output(self) -> Path:
"""Get the full output path."""
return self.directory.joinpath(self.name)

@property
def present(self) -> bool:
"""Determine if this file is currently present in the file system."""
return self.output.is_file()

@property
def platform(self) -> bool:
"""Determine if the platform is correct for handling this file."""
return not self.platforms or sys.platform in self.platforms

def evaluate(self, env: Dict[str, Any]) -> bool:
"""Determine if this file should be handled."""
return self.platform and eval( # pylint: disable=eval-used
self.condition, None, env
)

def update_root(self, root: Path) -> None:
"""
If the output directory is a relative path, update it to be an
Expand Down Expand Up @@ -68,4 +88,7 @@ def update(self, source: Path, logger: LoggerType) -> None:
else:
copyfile(source, output)

if self.executable:
set_exec_flags(output)

logger.info("'%s' -> '%s'.", rel(source), rel(output))
11 changes: 11 additions & 0 deletions rcmpy/data/schemas/ManagedFile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,20 @@ properties:
type: boolean
default: true

# Whether or not the file should be executable.
executable:
type: boolean
default: false

name:
type: string

# A string that will be evaluated for True/False and provided environment
# data.
condition:
type: string
default: "True"

platforms:
type: array
items:
Expand Down
39 changes: 39 additions & 0 deletions rcmpy/environment/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
A module for exposing useful information from the current system to templates.
"""

# built-in
from functools import lru_cache
import platform
import sys
from typing import Any, Dict


@lru_cache(maxsize=1)
def system_data() -> Dict[str, Any]:
"""Obtain useful system configuration data."""

return {
"sys": {
"base_exec_prefix": sys.base_exec_prefix,
"base_prefix": sys.base_prefix,
"byteorder": sys.byteorder,
"exec_prefix": sys.exec_prefix,
"executable": sys.executable,
"platform": sys.platform,
"prefix": sys.prefix,
"version": sys.version,
},
"platform": {
"bits": platform.architecture()[0],
"linkage": platform.architecture()[1],
"machine": platform.machine(),
"node": platform.node(),
"processor": platform.processor(),
"implementation": platform.python_implementation(),
"python_version": platform.python_version(),
"release": platform.release(),
"system": platform.system(),
"version": platform.version(),
},
}
8 changes: 8 additions & 0 deletions rcmpy/environment/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

# built-in
from copy import copy
from pathlib import Path
from typing import Dict, NamedTuple, Optional, Set, Tuple

Expand All @@ -15,6 +16,7 @@
# internal
from rcmpy.config import ManagedFile
from rcmpy.environment.base import BaseEnvironment
from rcmpy.environment.data import system_data


class EnvTemplate(NamedTuple):
Expand Down Expand Up @@ -171,4 +173,10 @@ def _init_loaded(self) -> bool:
self.updated_templates: Set[Path] = set()
self.updated_template_names: Set[str] = set()

# Add additional information to template data.
self.env_data = system_data()
self.template_data = copy(self.state.configs)
assert "env" not in self.template_data
self.template_data["env"] = self.env_data

return result and self._init_templates(self.config.templates)
1 change: 1 addition & 0 deletions rcmpy/state/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def init(self, data: _JsonObject) -> None:

data.setdefault("previous", {})
self.previous: Dict[str, Any] = data["previous"] # type: ignore
self.previous.setdefault("variant", "default")

# Variables.
self.variables: Dict[str, Any] = {}
Expand Down
3 changes: 3 additions & 0 deletions tests/data/valid/scenarios/simple/rcmpy.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
---
files:
- template: test.txt
executable: true

- template: dynamic.txt
extra_templates: [a.txt, b.txt, c.txt]
condition: "'platform' in sys"

- template: basic.txt
link: false
executable: true

- template: linux.txt
platforms: [linux]
Expand Down
Empty file modified tests/data/valid/scenarios/simple/templates/common/test.txt
100644 → 100755
Empty file.
Empty file modified tests/data/valid/scenarios/simple/templates/test/test.txt
100644 → 100755
Empty file.