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

Packaged build artifacts into artifacts directory #242

Merged
merged 1 commit into from
Nov 12, 2020
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
19 changes: 12 additions & 7 deletions Fw/Python/src/fprime/fbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ def generate(self, cmake_args):
("FPRIME_ENVIRONMENT_FILE", "environment_file"),
("FPRIME_AC_CONSTANTS_FILE", "ac_constants"),
("FPRIME_CONFIG_DIR", "config_dir"),
("FPRIME_INSTALL_DEST", "install_dest"),
]
cmake_args.update(
{
Expand All @@ -473,6 +474,17 @@ def purge(self):
""" Purge a build cache directory """
self.cmake.purge(self.build_dir)

def purge_install(self):
""" Purge the install directory """
assert "install_dest" in self.settings, "install_dest not present in settings"
self.cmake.purge(self.settings["install_dest"])

def install_dest_exists(self) -> Path:
""" Check if the install destination exists and returns the path if it does """
assert "install_dest" in self.settings, "install_dest not present in settings"
path = Path(self.settings["install_dest"])
return path if path.exists() else None

@staticmethod
def find_nearest_deployment(path: Path) -> Path:
"""Recurse up the directory stack looking for a valid deployment
Expand Down Expand Up @@ -616,11 +628,4 @@ class AmbiguousToolchainException(FprimeException):
"Generate unit test coverage reports",
build_types=[BuildType.BUILD_TESTING],
),
# Installation target
GlobalTarget(
"install",
"Install the current deployment build artifacts",
build_types=[BuildType.BUILD_NORMAL],
cmake="package_gen",
),
]
1 change: 1 addition & 0 deletions Fw/Python/src/fprime/fbuild/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def generate_build(self, source_dir, build_dir, args=None, ignore_output=False,
:param ignore_output: do not print the output where the user can see it
:param environment: environment to set when generating
"""

if not os.path.exists(build_dir):
os.makedirs(build_dir)
# We will CD for build, so this path must become absolute
Expand Down
51 changes: 35 additions & 16 deletions Fw/Python/src/fprime/fbuild/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

@author mstarch
"""
import configparser # Written after PY2 eol
import os
import configparser
from typing import Dict, List
from pathlib import Path


class IniSettings:
Expand All @@ -21,20 +23,24 @@ def find_fprime():
"""
Finds F prime by recursing parent to parent until a matching directory is found.
"""
needle = os.path.join(
"cmake", "FPrime.cmake"
) # If the F prime cmake file exists
path = os.getcwd()
while path != os.path.dirname(path):
if os.path.isfile(os.path.join(path, needle)):
return os.path.abspath(os.path.normpath(path))
path = os.path.dirname(path)
needle = Path("cmake/FPrime.cmake")
path = Path.cwd().resolve()
while path != path.parent:
if Path(path, needle).is_file():
return path
path = path.parent
raise FprimeLocationUnknownException(
"Please set 'framework_path' in [fprime] section in 'settings.ini"
)

@staticmethod
def read_safe_path(parser, section, key, ini_file):
def read_safe_path(
parser: configparser.ConfigParser,
section: str,
key: str,
ini_file: Path,
exists: bool = True,
) -> List[str]:
"""
Reads path(s), safely, from the config parser. Validates the path(s) exists or raises an exception. Paths are
separated by ':'. This will also expand relative paths relative to the settings file.
Expand All @@ -51,7 +57,7 @@ def read_safe_path(parser, section, key, ini_file):
if path == "" or path is None:
continue
full_path = os.path.abspath(os.path.normpath(os.path.join(base_dir, path)))
if not os.path.exists(full_path):
if exists and not os.path.exists(full_path):
raise FprimeSettingsException(
"Non-existant path '{}' found in section '{}' option '{}' of file '{}'".format(
path, section, key, ini_file
Expand All @@ -61,7 +67,7 @@ def read_safe_path(parser, section, key, ini_file):
return expanded

@staticmethod
def load(settings_file):
def load(settings_file: Path):
"""
Load settings from specified file or from specified build directory. Either a specific file or the build
directory must be not None.
Expand All @@ -71,16 +77,18 @@ def load(settings_file):
:return: a dictionary of needed settings
"""
settings_file = (
settings_file
if settings_file is not None
else os.path.join(IniSettings.DEF_FILE)
settings_file if settings_file is not None else Path(IniSettings.DEF_FILE)
)

dfl_install_dest = Path(settings_file.resolve().parent, "build-artifacts")

# Check file existence if specified
if not os.path.exists(settings_file):
print("[WARNING] Failed to find settings file: {}".format(settings_file))
fprime_location = IniSettings.find_fprime()
return {
"framework_path": fprime_location,
"install_dest": dfl_install_dest,
}
confparse = configparser.ConfigParser()
confparse.read(settings_file)
Expand All @@ -91,7 +99,7 @@ def load(settings_file):
if not fprime_location:
fprime_location = IniSettings.find_fprime()
else:
fprime_location = fprime_location[0]
fprime_location = Path(fprime_location[0])
# Read project root if it is available
proj_root = IniSettings.read_safe_path(
confparse, "fprime", "project_root", settings_file
Expand All @@ -108,6 +116,15 @@ def load(settings_file):
)
config_dir = None if not config_dir else config_dir[0]

install_dest = IniSettings.read_safe_path(
confparse, "fprime", "install_dest", settings_file, False
)

if install_dest:
install_dest = Path(install_dest[0])
else:
install_dest = dfl_install_dest

# Read separate environment file if necessary
env_file = IniSettings.read_safe_path(
confparse, "fprime", "environment_file", settings_file
Expand All @@ -117,13 +134,15 @@ def load(settings_file):
confparse, "fprime", "library_locations", settings_file
)
environment = IniSettings.load_environment(env_file)

settings = {
"settings_file": settings_file,
"framework_path": fprime_location,
"library_locations": libraries,
"default_toolchain": confparse.get(
"fprime", "default_toolchain", fallback="native"
),
"install_dest": install_dest,
"environment_file": env_file,
"environment": environment,
}
Expand Down
19 changes: 19 additions & 0 deletions Fw/Python/src/fprime/util/build_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,25 @@ def utility_entry(args):
)
if confirm() or parsed.force:
build.purge()

build = Build(BuildType.BUILD_NORMAL, deployment, verbose=parsed.verbose)
try:
build.load(parsed.platform, build_dir_as_path)
except InvalidBuildCacheException:
# Just load the install destination regardless of whether the build is valid.
pass

install_dir = build.install_dest_exists()
if install_dir is None:
return

print(
"[INFO] {} install directory at: {}".format(
parsed.command.title(), install_dir
)
)
if confirm() or parsed.force:
build.purge_install()
else:
target = get_target(parsed)
build = get_build(parsed, deployment, parsed.verbose, target)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[fprime]
install_dest: ../test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[fprime]
66 changes: 66 additions & 0 deletions Fw/Python/test/fprime/fbuild/test_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
(test) fprime.fbuild.settings:

Tests the F prime settings module.
@author joshuaa
"""

import pytest
import os
from pathlib import Path

from fprime.fbuild.settings import IniSettings


def full_path(path):
path = Path(__file__).parent / Path(path)
return path.resolve()


def test_settings():
test_cases = [
{
"file": "nonexistant.ini",
"expected": {
"framework_path": full_path("../../../../.."),
"install_dest": full_path("settings-data/build-artifacts"),
},
},
{
"file": "settings-empty.ini",
"expected": {
"settings_file": full_path("settings-data/settings-empty.ini"),
"default_toolchain": "native",
"framework_path": full_path("../../../../.."),
"install_dest": full_path("settings-data/build-artifacts"),
"library_locations": [],
"environment_file": full_path("settings-data/settings-empty.ini"),
"environment": {},
},
},
{
"file": "settings-custom-install.ini",
"expected": {
"settings_file": full_path("settings-data/settings-custom-install.ini"),
"default_toolchain": "native",
"framework_path": full_path("../../../../.."),
"install_dest": full_path("test"),
"library_locations": [],
"environment_file": full_path(
"settings-data/settings-custom-install.ini"
),
"environment": {},
},
},
]

# Setting chdir so that test is unaffected from working directory pytest is run from
os.chdir(full_path("."))

for case in test_cases:
fp = full_path("settings-data/" + case["file"])
print(fp)
results = IniSettings.load(fp)
assert case["expected"] == results, "{}: Expected {}, got {}".format(
fp, case["expected"], results
)
Loading