Skip to content
Merged
Changes from 2 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
140 changes: 94 additions & 46 deletions lib/dt_shell/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,34 @@
from . import logger, __version__
from .commands import CommandSet, CommandDescriptor
from .commands.repository import CommandsRepository
from .constants import DUCKIETOWN_TOKEN_URL, SHELL_LIB_DIR, DEFAULT_COMMAND_SET_REPOSITORY, \
DEFAULT_PROFILES_DIR, DB_SECRETS, DB_SECRETS_DOCKER, DB_SETTINGS, DB_USER_COMMAND_SETS_REPOSITORIES, \
DB_PROFILES, KNOWN_DISTRIBUTIONS, SUGGESTED_DISTRIBUTION, DB_UPDATES_CHECK, EMBEDDED_COMMAND_SET_NAME, \
Distro
from .constants import (
DUCKIETOWN_TOKEN_URL,
SHELL_LIB_DIR,
DEFAULT_COMMAND_SET_REPOSITORY,
DEFAULT_PROFILES_DIR,
DB_SECRETS,
DB_SECRETS_DOCKER,
DB_SETTINGS,
DB_USER_COMMAND_SETS_REPOSITORIES,
DB_PROFILES,
KNOWN_DISTRIBUTIONS,
SUGGESTED_DISTRIBUTION,
DB_UPDATES_CHECK,
EMBEDDED_COMMAND_SET_NAME,
Distro,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Import formatting is back to original style.

from .database.database import DTShellDatabase, NOTSET, DTSerializable
from .statistics import ShellProfileEventsDatabase
from .utils import safe_pathname, validator_token, yellow_bold, cli_style, parse_version, render_version, \
indent_block, DebugInfo
from .utils import (
safe_pathname,
validator_token,
yellow_bold,
cli_style,
parse_version,
render_version,
indent_block,
DebugInfo,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Import formatting is back to original style.

from .exceptions import ConfigNotPresent

TupleVersion = Tuple[int, int, int]
Expand All @@ -44,7 +64,7 @@ def dump(self) -> dict:
return {"username": self.username, "password": self.password}

@classmethod
def load(cls, v: dict) -> 'GenericCredentials':
def load(cls, v: dict) -> "GenericCredentials":
return GenericCredentials(**v)


Expand Down Expand Up @@ -79,7 +99,7 @@ def __new__(cls, *args, **kwargs):
return inst

@classmethod
def load(cls, profile: 'ShellProfile', location: str):
def load(cls, profile: "ShellProfile", location: str):
return ShellProfileSecrets.open(DB_SECRETS, location=location, init_args={"profile": profile})

@property
Expand Down Expand Up @@ -190,8 +210,10 @@ def __post_init__(self, _distro: Optional[str] = None):
if self.path is None:
profiles_dir: str = os.environ.get("DTSHELL_PROFILES", DEFAULT_PROFILES_DIR)
if profiles_dir != DEFAULT_PROFILES_DIR:
logger.info(f"Loading profiles from '{profiles_dir}' as prescribed by the environment "
f"variable DTSHELL_PROFILES.")
logger.info(
f"Loading profiles from '{profiles_dir}' as prescribed by the environment "
f"variable DTSHELL_PROFILES."
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Logger.info formatting is back to original style.

safe_name: str = safe_pathname(self.name)
self.path = os.path.join(profiles_dir, safe_name)
# make sure the profile directory exists
Expand Down Expand Up @@ -224,12 +246,16 @@ def __post_init__(self, _distro: Optional[str] = None):
commands_path = os.path.abspath(os.environ["DTSHELL_COMMANDS"])
# make sure the given path exists
if not os.path.exists(commands_path):
msg = f"The path {commands_path} given with the environment variable DTSHELL_COMMANDS does " \
f"not exist."
msg = (
f"The path {commands_path} given with the environment variable DTSHELL_COMMANDS does "
f"not exist."
)
raise Exception(msg)
# load commands from given path
msg = f"Loading commands from '{commands_path}' as instructed by the environment variable " \
f"DTSHELL_COMMANDS."
msg = (
f"Loading commands from '{commands_path}' as instructed by the environment variable "
f"DTSHELL_COMMANDS."
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Formatting is back to original style.

logger.info(msg)
self.command_sets.append(
CommandSet(
Expand Down Expand Up @@ -288,27 +314,31 @@ def __post_init__(self, _distro: Optional[str] = None):
vmax: Optional[TupleVersion] = cs.configuration.maximum_shell_version()
# check min
if vmin is not None and vnow < vmin:
logger.warning(f"\n -- WARNING\n\n" +
indent_block(
f"Command set '{cs.name}' wants a Duckietown Shell v{render_version(vmin)}"
f" or newer. We are running v{render_version(vnow)}.\n"
f"You will need to upgrade your shell to be able to use this command "
f"set or switch to an older version of this command set.\n"
f"This command set will now be disabled."
) +
f"\n\n -- WARNING\n")
logger.warning(
f"\n -- WARNING\n\n"
+ indent_block(
f"Command set '{cs.name}' wants a Duckietown Shell v{render_version(vmin)}"
f" or newer. We are running v{render_version(vnow)}.\n"
f"You will need to upgrade your shell to be able to use this command "
f"set or switch to an older version of this command set.\n"
f"This command set will now be disabled."
)
+ f"\n\n -- WARNING\n"
)
self.command_sets.remove(cs)
# check max
if vmax is not None and vnow > vmax:
logger.warning(f"\n -- WARNING\n\n" +
indent_block(
f"Command set '{cs.name}' only supports Duckietown Shell up to "
f"v{render_version(vmax)}. We are running v{render_version(vnow)}.\n"
f"You will need to downgrade your shell to be able to use this command "
f"set or switch to a newer version of this command set.\n"
f"This command set will now be disabled."
) +
f"\n\n -- WARNING\n")
logger.warning(
f"\n -- WARNING\n\n"
+ indent_block(
f"Command set '{cs.name}' only supports Duckietown Shell up to "
f"v{render_version(vmax)}. We are running v{render_version(vnow)}.\n"
f"You will need to downgrade your shell to be able to use this command "
f"set or switch to a newer version of this command set.\n"
f"This command set will now be disabled."
)
+ f"\n\n -- WARNING\n"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. All formatting changes in this section have been undone.

self.command_sets.remove(cs)

@property
Expand Down Expand Up @@ -350,9 +380,11 @@ def distro(self) -> Optional[Distro]:
if self.settings.distro is None:
return None
if self.settings.distro not in KNOWN_DISTRIBUTIONS:
logger.warning(f"Your profile is set to use the distribution '{self.settings.distro}' but this "
f"is not in the list of known distributions. Known distributions are "
f"{list(KNOWN_DISTRIBUTIONS.keys())}")
logger.warning(
f"Your profile is set to use the distribution '{self.settings.distro}' but this "
f"is not in the list of known distributions. Known distributions are "
f"{list(KNOWN_DISTRIBUTIONS.keys())}"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Formatting is back to original style.

return None
return KNOWN_DISTRIBUTIONS[self.settings.distro]

Expand Down Expand Up @@ -398,7 +430,9 @@ def configure(self, readonly: bool = False) -> bool:
matched: bool = False
for d in KNOWN_DISTRIBUTIONS.keys():
if d == self.name:
logger.info(f"Automatically selecting distribution '{d}' as it matches the profile name")
logger.info(
f"Automatically selecting distribution '{d}' as it matches the profile name"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot undo these formatting changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit e4dd4b8. Formatting is back to original style.

self.distro = d
matched = True
break
Expand All @@ -416,8 +450,9 @@ def configure(self, readonly: bool = False) -> bool:
if not distro.stable:
continue
# ---
eol: str = "" if distro.end_of_life is None else \
f"(end of life: {distro.end_of_life_fmt})"
eol: str = (
"" if distro.end_of_life is None else f"(end of life: {distro.end_of_life_fmt})"
)
label = [("class:choice", distro.name), ("class:disabled", f" {eol}")]
choice: Choice = Choice(title=label, value=distro.name)
if distro.name == SUGGESTED_DISTRIBUTION:
Expand All @@ -426,7 +461,8 @@ def configure(self, readonly: bool = False) -> bool:
distros.append(choice)
# let the user choose the distro
chosen_distro: str = questionary.select(
"Choose a distribution:", choices=distros, style=cli_style).unsafe_ask()
"Choose a distribution:", choices=distros, style=cli_style
).unsafe_ask()
# attach distro to profile
self.distro = chosen_distro
modified_config = True
Expand All @@ -448,18 +484,23 @@ def configure(self, readonly: bool = False) -> bool:
print(f"Token verified successfully. Your ID is: {yellow_bold(token.uid)}")
else:
print()
print(f"The Duckietown Shell needs a Duckietown Token to work properly. "
f"Get yours for free at {DUCKIETOWN_TOKEN_URL}")
print(
f"The Duckietown Shell needs a Duckietown Token to work properly. "
f"Get yours for free at {DUCKIETOWN_TOKEN_URL}"
)
while True:
# let the user insert the token
token_str: str = questionary.password("Enter your token:", validate=validator_token)\
.unsafe_ask()
token_str: str = questionary.password(
"Enter your token:", validate=validator_token
).unsafe_ask()
token: DuckietownToken = DuckietownToken.from_string(token_str)
# make sure this token is supported by this profile distro
tokens_supported: List[str] = self.distro.tokens_supported
if token.version not in tokens_supported:
print(f"Token version '{token.version}' not supported by this profile's distro. "
f"Only versions supported are {tokens_supported}.")
print(
f"Token version '{token.version}' not supported by this profile's distro. "
f"Only versions supported are {tokens_supported}."
)
continue
else:
print(f"Token verified successfully. Your ID is: {yellow_bold(token.uid)}")
Expand All @@ -473,7 +514,14 @@ def configure(self, readonly: bool = False) -> bool:
def update_command_descriptions(self, commands_path: str) -> None:
command_descriptions_path = commands_path + "/command_descriptions.yaml"
if not os.path.exists(command_descriptions_path):
logger.warning(f"File '{command_descriptions_path}' does not exist.")
# Only warn if the command set directory exists but the descriptions file is missing
# During auto-profile creation, the entire command set directory may not exist yet
if os.path.exists(commands_path):
logger.warning(f"File '{command_descriptions_path}' does not exist.")
else:
logger.debug(
f"Command set directory '{commands_path}' does not exist yet, skipping command descriptions update."
)
return
with open(command_descriptions_path) as stream:
self.command_descriptions.update(yaml.safe_load(stream))
Loading