Skip to content

Add scryer_path/1 manifest term#60

Closed
jjtolton wants to merge 2 commits intobakaq:mainfrom
jjtolton:feature/scryer-path-feature-only
Closed

Add scryer_path/1 manifest term#60
jjtolton wants to merge 2 commits intobakaq:mainfrom
jjtolton:feature/scryer-path-feature-only

Conversation

@jjtolton
Copy link
Contributor

Summary

Adds support for the scryer_path/1 term in scryer-manifest.pl for custom package search paths.

Motivation

Currently, bakage uses working_directory/2 to find the project root, which causes problems with editors like ediprolog that may run Prolog from different directories. This feature provides a declarative, manifest-based solution.

Usage

Add to your scryer-manifest.pl:

scryer_path([
    "vendor/scryer-manifest.pl",
    "libs/other-project/scryer-manifest.pl"
]).

Bakage will search for packages in this order:

  1. SCRYER_PATH environment variable (if set)
  2. Paths from scryer_path/1 (backtracking through each)
  3. Default {project_root}/scryer_libs

Changes

2 files modified:

  • bakage.pl - Added 4 new predicates, modified 1 (+39 lines)
  • README.md - Documented scryer_path/1 usage

New predicates:

  • current_project_manifest/1 - Read current project's manifest
  • manifest_scryer_paths/2 - Extract scryer_path/1 from manifest
  • manifest_path_to_scryer_libs/2 - Derive package location from manifest path
  • scryer_path_candidate/1 - Generate search paths via backtracking

Modified:

  • package_main_file/2 - Now uses scryer_path_candidate/1 for backtracking search

Benefits

✅ Declarative - specified in manifest, not environment variables
✅ Future-proof - references manifests, not internal package structure
✅ Editor-friendly - works with tools that change working directory
✅ Backward compatible - existing projects work unchanged

Related

Addresses working directory issues mentioned in #59

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

@constraintAutomaton
Copy link

Let's not forget to add this predicate in the validation pipeline.

Copy link
Owner

@bakaq bakaq left a comment

Choose a reason for hiding this comment

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

I can kinda see the utility here, but what exactly is the use case?

I think maybe a more structured workspace-like approach would cover most of the uses for this for the "many projects that share some libraries" use case. Maybe this PR is the start of a feature like that?

bakage.pl Outdated
Comment on lines +452 to +462
% Generate scryer path candidates via backtracking
scryer_path_candidate(Path) :-
getenv("SCRYER_PATH", Path).
scryer_path_candidate(ScryerLibsPath) :-
current_project_manifest(Manifest),
manifest_scryer_paths(Manifest, ManifestPaths),
member(ManifestPath, ManifestPaths),
manifest_path_to_scryer_libs(ManifestPath, ScryerLibsPath).
scryer_path_candidate(Path) :-
find_project_root(RootChars),
append([RootChars, "/scryer_libs"], Path).
Copy link
Owner

Choose a reason for hiding this comment

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

The backtracking here with the failure-driven loop in package_main_file/2 makes me a bit uncomfortable, but I guess it works to get the semantics that you want here.

@jjtolton
Copy link
Contributor Author

I can kinda see the utility here, but what exactly is the use case?

I think maybe a more structured workspace-like approach would cover most of the uses for this for the "many projects that share some libraries" use case. Maybe this PR is the start of a feature like that?

it's for packages that are cloned locally in the manifest. Scryer isn't finding their scryer_lib folder unless I set the paths.

@jjtolton
Copy link
Contributor Author

jjtolton commented Oct 25, 2025

Concrete Use Case

Let me clarify with a real-world example I'm encountering.

Project Structure

I'm developing a project with this structure:

~/my-main-project/
  ├── scryer-manifest.pl
  ├── scryer_libs/          # Main project dependencies
  └── main.pl

~/programs/testing.pl/      # Local package I'm developing
  ├── scryer-manifest.pl
  ├── testing.pl
  └── scryer_libs/          # testing.pl's dependencies

~/programs/debug_indent/    # Another local package
  ├── scryer-manifest.pl  
  ├── debug_indent.pl
  └── scryer_libs/          # debug_indent's dependencies

The Manifest

My main project's scryer-manifest.pl references these local packages:

dependencies([
    dependency("testing", path("/home/jay/programs/testing.pl")),
    dependency("debug_indent", path("/home/jay/programs/debug_indent")),
    dependency("quads", git("https://github.com/jjtolton/quads.git", branch("master")))
]).

The Problem

When my code (or code in one of those local dependencies) tries to import a package with use_module(pkg(some_package)), bakage only searches in ~/my-main-project/scryer_libs.

But some packages I need are installed in:

  • ~/programs/testing.pl/scryer_libs/
  • ~/programs/debug_indent/scryer_libs/

Without scryer_path/1, these packages are invisible to bakage, and I get existence errors unless I manually set SCRYER_PATH environment variables.

The Solution

With scryer_path/1, I can declare:

scryer_path([
    "/home/jay/programs/testing.pl/scryer-manifest.pl",
    "/home/jay/programs/debug_indent/scryer-manifest.pl"
]).

Now bakage automatically searches for packages in all three locations:

  1. ~/my-main-project/scryer_libs (default)
  2. ~/programs/testing.pl/scryer_libs (from scryer_path)
  3. ~/programs/debug_indent/scryer_libs (from scryer_path)

This is especially valuable for:

  • Polyrepo development: Multiple related packages developed in parallel
  • Monorepo-style projects: Shared libraries vendored locally without copying dependencies
  • Editor compatibility: Declarative manifest-based paths instead of environment variables that editors might not propagate

Rebased onto latest main (bakage.pl moved to src/bakage.pl).

This adds support for the scryer_path/1 term in scryer-manifest.pl
for custom package search paths.

Motivation: Currently, bakage uses working_directory/2 to find the
project root, which causes problems with editors like ediprolog that
may run Prolog from different directories. This feature provides a
declarative, manifest-based solution.

Usage: Add to your scryer-manifest.pl:

scryer_path([
    "vendor/scryer-manifest.pl",
    "libs/other-project/scryer-manifest.pl"
]).

Bakage will search for packages in this order:
1. SCRYER_PATH environment variable (if set)
2. Paths from scryer_path/1 (backtracking through each)
3. Default {project_root}/scryer_libs

Changes:
- src/bakage.pl: Added 4 new predicates, modified 1
- README.md: Documented scryer_path/1 usage

New predicates:
- current_project_manifest/1: Read current project's manifest
- manifest_scryer_paths/2: Extract scryer_path/1 from manifest
- manifest_path_to_scryer_libs/2: Derive package location from path
- scryer_path_candidate/1: Generate search paths via backtracking

Modified:
- package_main_file/2: Now uses scryer_path_candidate/1 for search
Changed package_main_file/2 to use explicit iteration instead of
relying on backtracking through scryer_path_candidate/1 clauses.

Before:
- package_main_file/2 called scryer_path_candidate/1 directly
- Relied on failure-driven loop for searching multiple paths

After:
- Added all_scryer_path_candidates/1 that collects all paths using findall/3
- package_main_file/2 now explicitly iterates through the collected list
- Makes the iteration pattern more explicit and easier to understand

This addresses bakaq's concern about the failure-driven loop pattern
while maintaining the same search behavior.
@jjtolton jjtolton force-pushed the feature/scryer-path-feature-only branch from b6d6708 to 58efa2e Compare October 25, 2025 03:33
@bakaq
Copy link
Owner

bakaq commented Oct 25, 2025

This is just transitive dependencies! It's coming eventually, and this is definitely not the right way to do it.

@bakaq
Copy link
Owner

bakaq commented Oct 25, 2025

Clarifying: with transitive dependencies this would just work.

Your main project would "inherit" and lock the dependencies of its dependencies recursively. You shouldn't need to refer to your dependencies' dependencies, that's what a package manager is for! This is why I still insist that Bakage is not ready for even early adoption yet, and why transitive dependencies are the biggest blocker for the MVP: a package manager is basically useless for any non-trivial use cases without them!

@jjtolton
Copy link
Contributor Author

its been pretty useful to me! but sounds good I'll close this out and hack it in locally until then

@jjtolton jjtolton closed this Oct 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants