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

Add packse list command #32

Merged
merged 1 commit into from
Dec 14, 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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ A scenario is a JSON description of a dependency tree.

See [`scenarios/example.json`](./scenarios/example.json)

### Listing scenarios

A list of available scenarios can be printed with the `list` command:

```bash
packse list
```

### Building scenarios

A scenario can be used to generate packages and build distributions:
Expand Down
4 changes: 2 additions & 2 deletions src/packse/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
from packse.error import (
BuildError,
DestinationAlreadyExists,
FileNotFound,
InvalidScenario,
ScenarioNotFound,
)
from packse.scenario import (
Package,
Expand All @@ -35,7 +35,7 @@ def build(targets: list[Path], rm_destination: bool):

for target in targets:
if not target.exists():
raise ScenarioNotFound(target)
raise FileNotFound(target)

try:
logger.debug("Loading %s", target)
Expand Down
38 changes: 38 additions & 0 deletions src/packse/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
PublishError,
UserError,
)
from packse.list import list
from packse.publish import publish
from packse.view import view

Expand Down Expand Up @@ -65,6 +66,15 @@ def _call_publish(args):
)


def _call_list(args):
skip_invalid = args.skip_invalid
if not args.targets:
skip_invalid = True
args.targets = Path.cwd().glob("**/*.json")

list(args.targets, args.no_versions, skip_invalid, args.no_sources)


def _root_parser():
parser = argparse.ArgumentParser(
description="Utilities for working example packaging scenarios",
Expand Down Expand Up @@ -138,6 +148,33 @@ def _add_view_parser(subparsers):
_add_shared_arguments(parser)


def _add_list_parser(subparsers):
parser = subparsers.add_parser("list", help="List scenarios")
parser.set_defaults(call=_call_list)
parser.add_argument(
"targets",
type=Path,
nargs="*",
help="The scenario files to load",
)
parser.add_argument(
"--no-versions",
action="store_true",
help="Do not include in the scenario versions in the displayed names.",
)
parser.add_argument(
"--skip-invalid",
action="store_true",
help="Skip invalid scenario files instead of failing.",
)
parser.add_argument(
"--no-sources",
action="store_true",
help="Do not show the source file for each scenario.",
)
_add_shared_arguments(parser)


def _add_shared_arguments(parser):
parser.add_argument(
"-v",
Expand All @@ -160,5 +197,6 @@ def get_parser() -> argparse.ArgumentParser:
_add_build_parser(subparsers)
_add_view_parser(subparsers)
_add_publish_parser(subparsers)
_add_list_parser(subparsers)

return parser
4 changes: 2 additions & 2 deletions src/packse/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def __init__(self, path: Path, reason: str) -> None:
super().__init__(message)


class ScenarioNotFound(UserError):
class FileNotFound(UserError):
def __init__(self, path: Path) -> None:
message = f"Scenario '{path}' not found"
message = f"File '{path}' not found"
super().__init__(message)


Expand Down
70 changes: 70 additions & 0 deletions src/packse/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
List all scenarios.
"""
import logging
from pathlib import Path

from packse.error import FileNotFound, InvalidScenario
from packse.scenario import (
Scenario,
load_scenarios,
scenario_prefix,
)

logger = logging.getLogger(__name__)


def list(
targets: list[Path],
no_versions: bool = False,
skip_invalid: bool = False,
no_sources: bool = False,
):
scenarios: dict[Path, list[Scenario]] = {}

# Validate and collect all targets first
for target in sorted(targets):
if not target.exists():
raise FileNotFound(target)

try:
logger.debug("Loading %s", target)
scenarios[target] = load_scenarios(target)
except Exception as exc:
if not skip_invalid:
raise InvalidScenario(target, reason=str(exc)) from exc

# Then list each one
for source, scenarios in scenarios.items():
prefix = "" if no_sources else " " * 4
if not no_sources:
print(to_display_path(source))

for scenario in scenarios:
if no_versions:
name = scenario.name
else:
name = scenario_prefix(scenario)

print(prefix + name)


def to_display_path(path: Path | str, relative_to: Path | str | None = None) -> str:
"""
Convert a path to a displayable path. The absolute path or relative path to the
current (or given) directory will be returned, whichever is shorter.
"""
path, relative_to = (
Path(path).resolve(),
Path(relative_to or ".").resolve(),
)

absolute_path = str(path)

try:
relative_path = str(path.relative_to(relative_to))
except ValueError:
# Not a child path, use the other one
return absolute_path

return relative_path if len(relative_path) < len(absolute_path) else absolute_path
4 changes: 2 additions & 2 deletions src/packse/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from packaging.requirements import Requirement

from packse.error import InvalidScenario, ScenarioNotFound
from packse.error import FileNotFound, InvalidScenario
from packse.scenario import (
Package,
Scenario,
Expand All @@ -23,7 +23,7 @@ def view(targets: list[Path]):
# Validate and collect all targets first
for target in targets:
if not target.exists():
raise ScenarioNotFound(target)
raise FileNotFound(target)

try:
logger.debug("Loading %s", target)
Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/test_build.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@
dict({
'exit_code': 1,
'stderr': '''
Scenario 'foo' not found.
File 'foo' not found.

''',
'stdout': '',
Expand Down
113 changes: 113 additions & 0 deletions tests/__snapshots__/test_list.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# serializer version: 1
# name: test_list_example
dict({
'exit_code': 0,
'stderr': '',
'stdout': '''
scenarios/example.json
example-5803604b

''',
})
# ---
# name: test_list_invalid_target
dict({
'exit_code': 1,
'stderr': '''
File at '[PWD]/test.json' is not a valid scenario: Input data was truncated.

''',
'stdout': '',
})
# ---
# name: test_list_invalid_target_skip_invalid
dict({
'exit_code': 0,
'stderr': '',
'stdout': '''
[PROJECT_ROOT]/scenarios/example.json
example-5803604b

''',
})
# ---
# name: test_list_no_sources
dict({
'exit_code': 0,
'stderr': '',
'stdout': '''
example-5803604b
requires-package-does-not-exist-e4666012
requires-exact-version-does-not-exist-c640da4b
requires-greater-version-does-not-exist-ceb05782
requires-less-version-does-not-exist-14de847d
transitive-requires-package-does-not-exist-15763ba4
requires-direct-incompatible-versions-3a64108d
requires-transitive-incompatible-with-root-version-8af9847a
requires-transitive-incompatible-with-transitive-cb77ed7e

''',
})
# ---
# name: test_list_no_target_finds_all_valid_scenarios
dict({
'exit_code': 0,
'stderr': '',
'stdout': '''
scenarios/example.json
example-5803604b
scenarios/requires-does-not-exist.json
requires-package-does-not-exist-e4666012
requires-exact-version-does-not-exist-c640da4b
requires-greater-version-does-not-exist-ceb05782
requires-less-version-does-not-exist-14de847d
transitive-requires-package-does-not-exist-15763ba4
scenarios/requires-incompatible-versions.json
requires-direct-incompatible-versions-3a64108d
requires-transitive-incompatible-with-root-version-8af9847a
requires-transitive-incompatible-with-transitive-cb77ed7e

''',
})
# ---
# name: test_list_no_versions
dict({
'exit_code': 0,
'stderr': '',
'stdout': '''
scenarios/example.json
example
scenarios/requires-does-not-exist.json
requires-package-does-not-exist
requires-exact-version-does-not-exist
requires-greater-version-does-not-exist
requires-less-version-does-not-exist
transitive-requires-package-does-not-exist
scenarios/requires-incompatible-versions.json
requires-direct-incompatible-versions
requires-transitive-incompatible-with-root-version
requires-transitive-incompatible-with-transitive

''',
})
# ---
# name: test_list_one_target_does_not_exist
dict({
'exit_code': 1,
'stderr': '''
File 'foo' not found.

''',
'stdout': '',
})
# ---
# name: test_list_target_does_not_exist
dict({
'exit_code': 1,
'stderr': '''
File 'foo' not found.

''',
'stdout': '',
})
# ---
15 changes: 9 additions & 6 deletions tests/__snapshots__/test_root.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'exit_code': 0,
'stderr': '',
'stdout': '''
usage: packse [-h] [-v] [-q] {build,view,publish} ...
usage: packse [-h] [-v] [-q] {build,view,publish,list} ...

Utilities for working example packaging scenarios

Expand All @@ -14,10 +14,11 @@
-q, --quiet Disable logging

commands:
{build,view,publish}
{build,view,publish,list}
build Build packages for a scenario
view View a scenario
publish Publish packages for a scenario
list List scenarios

''',
})
Expand All @@ -27,7 +28,7 @@
'exit_code': 0,
'stderr': '',
'stdout': '''
usage: packse [-h] [-v] [-q] {build,view,publish} ...
usage: packse [-h] [-v] [-q] {build,view,publish,list} ...

Utilities for working example packaging scenarios

Expand All @@ -37,10 +38,11 @@
-q, --quiet Disable logging

commands:
{build,view,publish}
{build,view,publish,list}
build Build packages for a scenario
view View a scenario
publish Publish packages for a scenario
list List scenarios

''',
})
Expand All @@ -50,7 +52,7 @@
'exit_code': 0,
'stderr': '',
'stdout': '''
usage: packse [-h] [-v] [-q] {build,view,publish} ...
usage: packse [-h] [-v] [-q] {build,view,publish,list} ...

Utilities for working example packaging scenarios

Expand All @@ -60,10 +62,11 @@
-q, --quiet Disable logging

commands:
{build,view,publish}
{build,view,publish,list}
build Build packages for a scenario
view View a scenario
publish Publish packages for a scenario
list List scenarios

''',
})
Expand Down
Loading