Skip to content

Commit

Permalink
Merge branch 'issue_1062-pkg-rm'
Browse files Browse the repository at this point in the history
  • Loading branch information
ajohns committed Apr 16, 2021
2 parents adb7af7 + c361cda commit ec77350
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 42 deletions.
9 changes: 8 additions & 1 deletion src/rez/cli/_entry_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,14 @@ def run_rez_pkg_ignore():


@scriptname("rez-mv")
def run_rez_pkg_mv():
def run_rez_mv():
check_production_install()
from rez.cli._main import run
return run("mv")


@scriptname("rez-rm")
def run_rez_rm():
check_production_install()
from rez.cli._main import run
return run("rm")
3 changes: 2 additions & 1 deletion src/rez/cli/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
"bundle": {},
"benchmark": {},
"pkg-ignore": {},
"mv": {}
"mv": {},
"rm": {}
}


Expand Down
4 changes: 2 additions & 2 deletions src/rez/cli/mv.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

def setup_parser(parser, completions=False):
parser.add_argument(
"--dest-path", metavar="PATH", required=True,
"-d", "--dest-path", metavar="PATH", required=True,
help="package repository to move PKG to.")
parser.add_argument(
"-k", "--keep-timestamp", action="store_true",
Expand All @@ -16,7 +16,7 @@ def setup_parser(parser, completions=False):
help="move package even if it isn't relocatable (use at your own risk)")
pkg_action = parser.add_argument(
"PKG",
help="package to move")
help="package to move (eg 'foo-1.2.3')")
parser.add_argument(
"PATH", nargs='?',
help="The repository containing the package. If not specified, this "
Expand Down
75 changes: 75 additions & 0 deletions src/rez/cli/rm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'''
Remove package(s) from a repository.
'''
from __future__ import print_function
import sys


def setup_parser(parser, completions=False):
group = parser.add_mutually_exclusive_group()
group.add_argument(
"-p", "--package",
help="remove the specified package (eg 'foo-1.2.3'). This will work "
"even if the package is currently ignored.")
group.add_argument(
"-i", "--ignored-since", type=int, metavar="DAYS",
help="remove all packages that have been ignored for >= DAYS")

parser.add_argument(
"--dry-run", action="store_true",
help="dry run mode")
parser.add_argument(
"PATH", nargs='?',
help="the repository containing the package(s) to remove.")


def remove_package(opts, parser):
from rez.vendor.version.requirement import VersionedObject
from rez.package_remove import remove_package

if opts.dry_run:
parser.error("--dry-run is not supported with --package")

if not opts.PATH:
parser.error("Must specify PATH with --package")

obj = VersionedObject(opts.package)

if remove_package(obj.name, obj.version, opts.PATH):
print("Package removed.")
else:
print("Package not found.", file=sys.stderr)
sys.exit(1)


def remove_ignored_since(opts, parser):
from rez.package_remove import remove_packages_ignored_since

if opts.PATH:
paths = [opts.PATH]
else:
paths = None

num_removed = remove_packages_ignored_since(
days=opts.ignored_since,
paths=paths,
dry_run=opts.dry_run,
verbose=opts.verbose
)

if num_removed:
if opts.dry_run:
print("%d packages would be removed." % num_removed)
else:
print("%d packages were removed." % num_removed)
else:
print("No packages were removed.")


def command(opts, parser, extra_arg_groups=None):
if opts.package:
remove_package(opts, parser)
elif opts.ignored_since is not None:
remove_ignored_since(opts, parser)
else:
parser.error("Must specify either --package or --ignored-since")
61 changes: 61 additions & 0 deletions src/rez/package_remove.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from rez.package_repository import package_repository_manager
from rez.vendor.version.version import Version
from rez.utils.logging_ import print_info
from rez.vendor.six import six
from rez.config import config


basestring = six.string_types[0]


def remove_package(name, version, path):
"""Remove a package from its repository.
Note that you are able to remove a package that is hidden (ie ignored).
This is why a Package instance is not specified (if the package were hidden,
you wouldn't be able to get one).
Args:
name (str): Name of package.
version (Version or str): Version of the package, eg '1.0.0'
path (str): Package repository path containing the package.
Returns:
bool: True if the package was removed, False if package not found.
"""
if isinstance(version, basestring):
version = Version(version)

repo = package_repository_manager.get_repository(path)
return repo.remove_package(name, version)


def remove_packages_ignored_since(days, paths=None, dry_run=False, verbose=False):
"""Remove packages ignored for >= specified number of days.
Args:
days (int): Remove packages ignored >= this many days
paths (list of str, optional): Paths to search for packages, defaults
to `config.packages_path`.
dry_run: Dry run mode
verbose (bool): Verbose mode
Returns:
int: Number of packages removed. In dry-run mode, returns the number of
packages that _would_ be removed.
"""
num_removed = 0

for path in (paths or config.packages_path):
repo = package_repository_manager.get_repository(path)

if verbose:
print_info("Searching %s...", repo)

num_removed += repo.remove_ignored_since(
days=days,
dry_run=dry_run,
verbose=verbose
)

return num_removed
29 changes: 29 additions & 0 deletions src/rez/package_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,35 @@ def unignore_package(self, pkg_name, pkg_version):
"""
raise NotImplementedError

def remove_package(self, pkg_name, pkg_version):
"""Remove a package.
Note that this should work even if the specified package is currently
ignored.
Args:
pkg_name (str): Package name
pkg_version(`Version`): Package version
Returns:
bool: True if the package was removed, False if it wasn't found.
"""
raise NotImplementedError

def remove_ignored_since(self, days, dry_run=False, verbose=False):
"""Remove packages ignored for >= specified number of days.
Args:
days (int): Remove packages ignored >= this many days
dry_run: Dry run mode
verbose (bool): Verbose mode
Returns:
int: Number of packages removed. In dry-run mode, returns the
number of packages that _would_ be removed.
"""
raise NotImplementedError

def pre_variant_install(self, variant_resource):
"""Called before a variant is installed.
Expand Down
9 changes: 6 additions & 3 deletions src/rez/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from rez.utils.schema import schema_keys
from rez.utils.resources import ResourceHandle, ResourceWrapper
from rez.exceptions import PackageFamilyNotFoundError, ResourceError
from rez.vendor.version.version import VersionRange
from rez.vendor.version.version import Version, VersionRange
from rez.vendor.version.requirement import VersionedObject
from rez.vendor.six import six
from rez.serialise import FileFormat
Expand Down Expand Up @@ -603,6 +603,9 @@ def get_package_from_repository(name, version, path):
"""
repo = package_repository_manager.get_repository(path)

if isinstance(version, basestring):
version = Version(version)

package_resource = repo.get_package(name, version)
if package_resource is None:
return None
Expand Down Expand Up @@ -905,8 +908,8 @@ def get_latest_package_from_string(txt, paths=None, error=False):
Args:
txt (str): Request, eg 'foo-1.2+'
paths (list of str, optional): paths to search for package families,
defaults to `config.packages_path`.
paths (list of str, optional): paths to search for packages, defaults
to `config.packages_path`.
error (bool): If True, raise an error if no package is found.
Returns:
Expand Down
57 changes: 57 additions & 0 deletions src/rez/tests/test_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from rez.package_py_utils import expand_requirement
from rez.package_resources import package_release_keys
from rez.package_move import move_package
from rez.package_remove import remove_package, remove_packages_ignored_since
from rez.package_repository import package_repository_manager
from rez.tests.util import TestBase, TempdirMixin
from rez.utils.formatting import PackageRequest
from rez.utils.sourcecode import SourceCode
Expand Down Expand Up @@ -452,10 +454,18 @@ def test_package_ignore(self):

repo = pkg.repository

# ignore a pkg that doesn't exist
i = repo.ignore_package("i_dont_exist", Version("1"))
self.assertEqual(i, -1)

# ignore a pkg that doesn't exist, but allow it
i = repo.ignore_package("i_dont_exist", Version("1"), allow_missing=True)
self.assertEqual(i, 1)

# unignore a pkg that doesn't exist
i = repo.unignore_package("i_dont_exist", Version("1"))
self.assertEqual(i, -1)

# ignore an existing package
i = repo.ignore_package(pkg_name, pkg_version)
self.assertEqual(i, 1)
Expand Down Expand Up @@ -508,6 +518,53 @@ def test_package_move(self):
src_pkg = get_package_from_repository(pkg_name, pkg_version, repo_path)
self.assertEqual(src_pkg, None)

def test_package_remove(self):
"""Test package remove."""
pkg_name = "pydad"
pkg_version = Version("2")

# copy packages to a temp repo
repo_path = os.path.join(self.root, "tmp4_packages")
shutil.copytree(self.solver_packages_path, repo_path)

# verify that source pkg exists
src_pkg = get_package_from_repository(pkg_name, pkg_version, repo_path)
self.assertNotEqual(src_pkg, None)

# remove it
was_removed = remove_package(pkg_name, pkg_version, repo_path)
self.assertTrue(was_removed)

# verify that source pkg no longer exists (and isn't simply ignored)
repo = package_repository_manager.get_repository(repo_path)
i = repo.unignore_package(pkg_name, pkg_version)
self.assertEqual(i, -1)

def test_remove_packages_ignored_since(self):
pkg_name = "pydad"
pkg_version = Version("2")

# copy packages to a temp repo
repo_path = os.path.join(self.root, "tmp5_packages")
shutil.copytree(self.solver_packages_path, repo_path)

# verify that source pkg exists
src_pkg = get_package_from_repository(pkg_name, pkg_version, repo_path)
self.assertNotEqual(src_pkg, None)

# ignore it
repo = package_repository_manager.get_repository(repo_path)
i = repo.ignore_package(pkg_name, pkg_version)
self.assertEqual(i, 1)

# remove all ignored packages
num_removed = remove_packages_ignored_since(days=0, paths=[repo_path])
self.assertEqual(num_removed, 1)

# verify that source pkg no longer exists (and isn't simply ignored)
i = repo.unignore_package(pkg_name, pkg_version)
self.assertEqual(i, -1)


class TestMemoryPackages(TestBase):
def test_1_memory_variant_parent(self):
Expand Down
Loading

0 comments on commit ec77350

Please sign in to comment.