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

Issue/3110 modules v2 moduletool commands #3473

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 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
6 changes: 6 additions & 0 deletions changelogs/unreleased/3110-modules-v2-moduletool-commands.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
description: Reviewed all moduletool commands for v2 compatibility
change-type: major
sections:
deprecation-note: "The `inmanta module list -r` command has been deprecated in favor of `inmanta project freeze`"
destination-branches:
- master
23 changes: 6 additions & 17 deletions src/inmanta/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ def compose_install_command(
allow_pre_releases: bool = False,
constraints_files: Optional[List[str]] = None,
requirements_files: Optional[List[str]] = None,
reinstall: bool = False,
) -> List[str]:
"""
Generate `pip install` command from the given arguments.
Expand All @@ -117,7 +116,6 @@ def compose_install_command(
:param allow_pre_releases: Allow the installation of packages with pre-releases and development versions.
:param constraints_files: Files that should be passed to pip using the `-c` option.
:param requirements_files: Files that should be passed to pip using the `-r` option.
:param reinstall: Reinstall previously installed packages. If not set, packages are not overridden.
"""
requirements = requirements if requirements is not None else []
paths = paths if paths is not None else []
Expand All @@ -141,7 +139,6 @@ def compose_install_command(
"-m",
"pip",
"install",
*(["--force-reinstall"] if reinstall else []),
*(["--upgrade"] if upgrade else []),
*(["--pre"] if allow_pre_releases else []),
*chain.from_iterable(["-c", f] for f in constraints_files),
Expand Down Expand Up @@ -271,20 +268,16 @@ def install_from_index(
raise PackageNotFound("Packages %s were not found in the given indexes." % ", ".join(not_found))
raise e

def install_from_source(
self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None, *, reinstall: bool = False
) -> None:
def install_from_source(self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None) -> None:
"""
Install one or more packages from source. Any path arguments should be local paths to a package directory or wheel.

:param reinstall: reinstall previously installed packages. If not set, packages are not overridden.
"""
if len(paths) == 0:
raise Exception("install_from_source requires at least one package to install")
constraint_files = constraint_files if constraint_files is not None else []
with requirements_txt_file(content=self._get_constraint_on_inmanta_package()) as filename:
cmd: List[str] = PipCommandBuilder.compose_install_command(
python_path=self.python_path, paths=paths, constraints_files=[*constraint_files, filename], reinstall=reinstall
python_path=self.python_path, paths=paths, constraints_files=[*constraint_files, filename]
)
self._run_command_and_log_output(cmd, stderr=subprocess.PIPE)

Expand Down Expand Up @@ -393,11 +386,9 @@ def install_from_index(
finally:
self.notify_change()

def install_from_source(
self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None, *, reinstall: bool = False
) -> None:
def install_from_source(self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None) -> None:
try:
super().install_from_source(paths, constraint_files, reinstall=reinstall)
super().install_from_source(paths, constraint_files)
finally:
self.notify_change()

Expand Down Expand Up @@ -789,12 +780,10 @@ def install_from_index(
constraint_files,
)

def install_from_source(
self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None, *, reinstall: bool = False
) -> None:
def install_from_source(self, paths: List[LocalPackagePath], constraint_files: Optional[List[str]] = None) -> None:
if not self.__using_venv:
raise Exception(f"Not using venv {self.env_path}. use_virtual_env() should be called first.")
super(VirtualEnv, self).install_from_source(paths, constraint_files, reinstall=reinstall)
super(VirtualEnv, self).install_from_source(paths, constraint_files)

def install_from_list(self, requirements_list: List[str]) -> None:
if not self.__using_venv:
Expand Down
123 changes: 64 additions & 59 deletions src/inmanta/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
Mapping,
NewType,
Optional,
Sequence,
Set,
TextIO,
Tuple,
Expand Down Expand Up @@ -140,11 +141,15 @@ def __str__(self) -> str:
def __hash__(self) -> int:
return self._requirement.__hash__()

@property
def specs(self) -> Sequence[Tuple[str, str]]:
return self._requirement.specs

def version_spec_str(self) -> str:
"""
Returns a string representation of this module requirement's version spec. Includes only the version part.
"""
return ",".join("".join(spec) for spec in self._requirement.specs)
return ",".join("".join(spec) for spec in self.specs)

@classmethod
def parse(cls: Type[TInmantaModuleRequirement], spec: str) -> TInmantaModuleRequirement:
Expand Down Expand Up @@ -517,7 +522,7 @@ def install(self, project: "Project", module_spec: List[InmantaModuleRequirement
"Currently installed %s-%s does not match constraint %s: updating to compatible version.",
module_name,
preinstalled_version,
",".join(constraint.version_spec_str() for constraint in module_spec),
",".join(constraint.version_spec_str() for constraint in module_spec if constraint.specs),
)
try:
env.process_env.install_from_index(requirements, self.urls, allow_pre_releases=allow_pre_releases)
Expand Down Expand Up @@ -560,7 +565,7 @@ def path_for(self, name: str) -> Optional[str]:
raise InvalidModuleException(
f"Invalid module: found module package but it has no {ModuleV2.MODULE_FILE}. This occurs when you install or build"
" modules from source incorrectly. Always use the `inmanta module install` and `inmanta module build` commands to"
" respectively install and build modules from source."
" respectively install and build modules from source. Make sure to uninstall the broken package first."
)

@classmethod
Expand Down Expand Up @@ -596,7 +601,7 @@ def install(self, project: "Project", module_spec: List[InmantaModuleRequirement
"Currently installed %s-%s does not match constraint %s: updating to compatible version.",
module_name,
preinstalled_version,
",".join(constraint.version_spec_str() for constraint in module_spec),
",".join(constraint.version_spec_str() for constraint in module_spec if constraint.specs),
)
return ModuleV1.update(
project, module_name, module_spec, preinstalled.path, fetch=False, install_mode=project.install_mode
Expand Down Expand Up @@ -1944,7 +1949,7 @@ def use_virtual_env(self) -> None:
"""
self.virtualenv.use_virtual_env()

def sorted_modules(self) -> list:
def sorted_modules(self) -> List["Module"]:
"""
Return a list of all modules, sorted on their name
"""
Expand Down Expand Up @@ -1988,7 +1993,7 @@ def requires(self) -> "List[InmantaModuleRequirement]":
print("Module file for %s has bad line in requirements specification %s" % (self._path, spec))
reqe = InmantaModuleRequirement(req[0])
reqs.append(reqe)
return reqs
return [*reqs, *self.get_module_v2_requirements()]

def collect_requirements(self) -> "Dict[str, List[InmantaModuleRequirement]]":
"""
Expand Down Expand Up @@ -2301,58 +2306,6 @@ def _get_fq_mod_name_for_py_file(self, py_file: str, plugin_dir: str, mod_name:
rel_py_file = os.path.relpath(py_file, start=plugin_dir)
return loader.PluginModuleLoader.convert_relative_path_to_module(os.path.join(mod_name, loader.PLUGIN_DIR, rel_py_file))

def versions(self) -> List["Version"]:
"""
Provide a list of all versions available in the repository
"""
versions = gitprovider.get_all_tags(self._path)

def try_parse(x: str) -> "Optional[Version]":
try:
return parse_version(x)
except Exception:
return None

versions = [x for x in [try_parse(v) for v in versions] if x is not None]
versions = sorted(versions, reverse=True)

return versions

def status(self) -> None:
"""
Run a git status on this module
"""
try:
output = gitprovider.status(self._path)

files = [x.strip() for x in output.split("\n") if x != ""]

if len(files) > 0:
print(f"Module {self.name} ({self._path})")
for f in files:
print("\t%s" % f)

print()
else:
print(f"Module {self.name} ({self._path}) has no changes")
except Exception:
print("Failed to get status of module")
LOGGER.exception("Failed to get status of module %s")

def push(self) -> None:
"""
Run a git status on this module
"""
sys.stdout.write("%s (%s) " % (self.name, self._path))
sys.stdout.flush()
try:
print(gitprovider.push(self._path))
except CalledProcessError:
print("Cloud not push module %s" % self.name)
else:
print("done")
print()

def execute_command(self, cmd: str) -> None:
print("executing %s on %s in %s" % (cmd, self.name, self._path))
print("=" * 10)
Expand Down Expand Up @@ -2562,6 +2515,58 @@ def add_module_requirement_persistent(self, requirement: InmantaModuleRequiremen
# Remove requirement from module.yml file
self.remove_module_requirement_from_requires_and_write(requirement.key)

def versions(self) -> List["Version"]:
"""
Provide a list of all versions available in the repository
"""
versions = gitprovider.get_all_tags(self._path)

def try_parse(x: str) -> "Optional[Version]":
try:
return parse_version(x)
except Exception:
return None

versions = [x for x in [try_parse(v) for v in versions] if x is not None]
versions = sorted(versions, reverse=True)

return versions

def status(self) -> None:
"""
Run a git status on this module
"""
try:
output = gitprovider.status(self._path)

files = [x.strip() for x in output.split("\n") if x != ""]

if len(files) > 0:
print(f"Module {self.name} ({self._path})")
for f in files:
print("\t%s" % f)

print()
else:
print(f"Module {self.name} ({self._path}) has no changes")
except Exception:
print("Failed to get status of module")
LOGGER.exception("Failed to get status of module %s")

def push(self) -> None:
"""
Run a git push on this module
"""
sys.stdout.write("%s (%s) " % (self.name, self._path))
sys.stdout.flush()
try:
print(gitprovider.push(self._path))
except CalledProcessError:
print("Cloud not push module %s" % self.name)
else:
print("done")
print()


@stable_api
class ModuleV2(Module[ModuleV2Metadata]):
Expand All @@ -2587,7 +2592,7 @@ def __init__(
raise InvalidModuleException(
f"The module at {path} contains no _init.cf file. This occurs when you install or build modules from source"
" incorrectly. Always use the `inmanta module install` and `inmanta module build` commands to respectively"
" install and build modules from source."
" install and build modules from source. Make sure to uninstall the broken package first."
)

@classmethod
Expand Down
Loading