β¨ feat: add fork environment support#65
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors the βfork environmentβ workflow into a dedicated CLI command (meowda fork / meowda env fork), splitting create vs fork logic in the service layer and moving fork mechanics into a new src/venv/fork.rs module.
Changes:
- Introduce
meowda fork/meowda env forkcommands and wire them into the CLI entrypoint. - Split
VenvBackendintoVenvService, extracting venv creation intosrc/venv/create.rsand fork implementation intosrc/venv/fork.rs. - Update scope handling and documentation/examples to reflect the new commands and module layout.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/venv/mod.rs | Renames backend to VenvService, adds create/fork APIs with option structs, and hooks into new fork module. |
| src/venv/fork.rs | New fork implementation: resolves source env/executable, creates target venv, copies site-packages/scripts, rewrites paths, adds tests. |
| src/venv/create.rs | New helper to run uv venv with consistent flags. |
| src/store/venv_store.rs | Makes ScopeType Copy to support reuse across CLI/service flows. |
| src/main.rs | Rewires entrypoint to venv::VenvService and new fork command routes. |
| src/cli/mod.rs | Exposes new cli::fork module. |
| src/cli/fork.rs | Implements meowda fork command handler and invokes VenvService::fork. |
| src/cli/env.rs | Updates env subcommands to use VenvService and new CreateOptions. |
| src/cli/args.rs | Adds Fork command and ForkArgs, updates CreateArgs python handling. |
| src/cli/install.rs | Renames backend parameter usage to VenvService. |
| src/cli/link.rs | Renames backend parameter usage to VenvService. |
| README.md | Documents meowda fork usage and updates command reference. |
Comments suppressed due to low confidence (1)
src/cli/args.rs:89
- Same
default_value = "false"issue asCreateArgs::clear: this may turn--clearinto an option that expects an explicit boolean value, instead of a simple flag. Remove thedefault_value(or setaction = clap::ArgAction::SetTrue) someowda fork ... --clearworks as intended.
#[arg(
short,
long,
default_value = "false",
help = "Clear existing virtual environment"
)]
pub clear: bool,
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #[arg( | ||
| short, | ||
| long, | ||
| default_value = "3.13", | ||
| help = "Python version/path to use" | ||
| default_value = "false", | ||
| help = "Clear existing virtual environment" | ||
| )] | ||
| pub clear: bool, |
There was a problem hiding this comment.
clear: bool flags already default to false with clap derive. Setting default_value = "false" can change the argument into a value-taking option (potentially requiring --clear <true|false>), which would break the documented --clear usage. Drop default_value and keep this as a simple presence flag (or explicitly set action = clap::ArgAction::SetTrue).
| include_system_site_packages: prefix.join("pyvenv.cfg").exists() | ||
| && (prefix != base_prefix || !real_prefix.is_empty() || include_system_site_packages), |
There was a problem hiding this comment.
include_system_site_packages is computed as pyvenv.cfg exists && (prefix != base_prefix || ...), which will be true for most virtual environments (since sys.prefix != sys.base_prefix). This will cause create_with_source to pass --system-site-packages when forking from a normal venv, unintentionally exposing system packages. Compute this field strictly from pyvenv.cfg's include-system-site-packages value (and keep any "is venv" detection as a separate boolean if needed).
| include_system_site_packages: prefix.join("pyvenv.cfg").exists() | |
| && (prefix != base_prefix || !real_prefix.is_empty() || include_system_site_packages), | |
| include_system_site_packages, |
| let link_is_dir = fs::metadata(source) | ||
| .map(|meta| meta.is_dir()) | ||
| .unwrap_or(false); | ||
| create_symlink(&rewritten_target, target, link_is_dir)?; |
There was a problem hiding this comment.
On Windows, symlink_dir vs symlink_file needs the correct is_dir value. Here link_is_dir is derived from fs::metadata(source) (follows the link) and falls back to false on error, which will mis-handle broken dir symlinks and can make the fork fail. Consider resolving link_target relative to the symlink's parent and checking metadata on that path, or attempting symlink_dir then symlink_file (or vice versa) when the target can't be inspected.
There was a problem hiding this comment.
π‘ Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc51e3a710
βΉοΈ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with π.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if options.clear { | ||
| Self::remove_venv(store, name)?; |
There was a problem hiding this comment.
Reject self-fork before deleting an existing target env
When fork is called with --clear, the target environment is removed before we validate that the source and target are different. If a user runs something like meowda fork myenv --from myenv --clear (or points --from at the same path), this branch deletes myenv and then create_with_source later aborts on the same-source check in src/venv/fork.rs, resulting in destructive data loss instead of a clean validation error. The source/target identity check should happen before remove_venv is executed.
Useful? React with πΒ / π.
Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
meowda fork/meowda env forkcommand and remove fork-specific flags fromcreateVenvService, with fork mechanics moved intosrc/venv/fork.rsvenvand update the README examples and command referenceCloses #59.
Testing
cargo +stable fmt --allcargo +stable clippy --all-targets --all-features -- -D warningscargo +stable test