Skip to content
This repository has been archived by the owner on Jan 18, 2025. It is now read-only.

support repos with .cargo/config.toml but no Cargo.toml at root #205

Open
alsuren opened this issue Jul 11, 2022 · 7 comments
Open

support repos with .cargo/config.toml but no Cargo.toml at root #205

alsuren opened this issue Jul 11, 2022 · 7 comments

Comments

@alsuren
Copy link

alsuren commented Jul 11, 2022

Feel free to mark this as too niche and close it.

I thought I'd share a slightly contrarian take on the xtask pattern for full-stack rust (the original pattern is described in https://github.com/matklad/cargo-xtask/ and a variation for embedded development is described at https://ferrous-systems.com/blog/test-embedded-app/):

4 workspaces:

  • frontend/
  • backend/
  • xtask/
  • crates/ (contains common code that is shared between frontend and backend)

No Cargo.toml at the top level

A .cargo/config.toml at the top level with this in:

[alias]
xtask = "run --timings --manifest-path=xtask/Cargo.toml"
xhelp = "xtask -- --help"
xfmt = "xtask -- fmt"
xcheck = "xtask -- check"
xtest = "xtask -- test"
xhost = "xtask -- host"
xbuild = "xtask -- build"
xdeploy = "xtask -- deploy"
xrollout = "xtask -- rollout"

[env]
TARGET_DIR = { value = "target", relative = true, force = true }
ROOT_DIR = { value = "", relative = true, force = true }

# ... and some other stuff around profiles etc.

This has the advantage that each workspace is isolated, and you can get away without workspace-hack packages. It also means that all of your custom build commands work fine from the root of the repo.

Unfortunately, it also means that cargo watch doesn't play ball at the root of the repo (and the xtask alias is fragile enough that it doesn't work anywhere other than the root of the repo).

$ cargo watch -x xcheck
error: project root does not exist

As I said in at the top, feel free to close this. I can't even think how cargo watch would be able to make any sensible decision other than "watch the whole git repo" under this scheme.

The fix at the project level would be to merge the crates/ and backend/ workspaces, and promote them to the top level of the repo (following the structure in the ferrous-systems article, above), then be a bit more careful with feature flag interactions (probably using a workspace-hack package or similar). It is also possible to use watchexec, as long as you add some workarounds for nested .gitignore problems (watchexec/watchexec#250)

@passcod
Copy link
Member

passcod commented Jul 11, 2022

Interesting one! I think I can support it, but will report back if I can't. How would you call this pattern (for reference)?

@passcod
Copy link
Member

passcod commented Jul 11, 2022

Marking as upstream for inclusion in the project-types crate.

@alsuren
Copy link
Author

alsuren commented Jul 11, 2022

How would you call this pattern (for reference)?

I guess the lack of workspace at the root of the repo makes me think "rootless" or something? Maybe "rootless xtask" or "rootless multi-workspace repo"?

@passcod
Copy link
Member

passcod commented Jul 12, 2022

I've called it a meta-workspace for now. Nevermind, "super workspace" is what I'm going with.

@passcod
Copy link
Member

passcod commented Jul 12, 2022

Okay, what do you think of this (extract from future help page):

    -p, --package <spec pattern>
            Watch a package in a Cargo workspace.

            This is almost equivalent to --watch, but with Cargo-aware metadata resolution instead
            of simple pathnames.

            The `spec` argument uses cargo-pkgid syntax, but implements an extension on that format
            to disambiguate in the case of “super workspaces” (see the --super flag). The syntax is
            also available in normal crates or workspaces but not very useful.

            `bar::foo` matches the `foo` crate under the `bar` workspace. The workspace name is
            either the name of the top-level crate (when the [workspace] Cargo.toml also contains a
            [package] definition), or the name of the folder containing the [workspace] Cargo.toml
            (for “virtual” workspaces). `bar::` matches the `bar` workspace itself.

            The argument to --package supports glob patterns, like for cargo-pkgid and other
            built-in commands. You'll likely have to quote glob patterns to prevent your shell from
            eagerly expanding them.

            The syntax does not support the URL version of the pkgid spec format, as that makes no
            sense for Cargo Watch's purposes.
        --super
            Consider super-workspaces when resolving crates.

            “Super workspaces” is an xtask pattern where the top level of the project contains only
            a .cargo directory containing a config.toml. This setup means that component workspaces
            are isolated while sharing an xtask setup, without need for workspace-hack packages.

            When this flag is set, Cargo Watch alters its crate resolution mechanisms to look for
            this top level super workspace. Nested super workspaces are not supported.

            --package resolves specs across all component workspaces.

            --workspace watches the entire super workspace.

            --workspace-origin's default is set to the super workspace’s root.

            The default ignore patterns also change to include the target/ directory under each
            component workspace, instead of at the top level.

            When run from the root of a super workspace, Cargo Watch will infer the --super flag,
            and will watch the entire super workspace unless --package is given.

@alsuren
Copy link
Author

alsuren commented Jul 12, 2022

Replying from my phone.

Looks reasonable. I think the main things I noticed were:

   `bar::foo` matches the `foo` crate under the `bar` workspace. The workspace name is
            either the name of the top-level crate (when the [workspace] Cargo.toml also contains a
            [package] definition), or the name of the folder containing the [workspace] Cargo.toml
            (for “virtual” workspaces).

            `qux::bar::foo` matches the `foo` crate under the `bar` workspace nested under the `qux`
            workspace, and so on.

I'm not a fan of the foo bar baz metavariables. Could we make them meaningful like ws, crate, ... subcrate?

I did't think it's possible to double nest workspaces in cargo? I might be misunderstanding your example.

It might also be worth including a / in the example root workspace name, to point out that it could be a path.

            The default ignore patterns also change to include the target/ directory under each
            component workspace, instead of at the top level.

In my case, the target dir is specified by the [env] section to be ./target. This setup is really niche and hairy. I'm really sorry.

At some point the complexity required to support edge cases like this stops being worthwhile, and just having a documented workaround is the best answer.

If --super is automatically inferred by default, I guess you don't need --super - you need --no-super to turn the functionality off when it misbehaves?

@passcod
Copy link
Member

passcod commented Jul 12, 2022

Could we make them meaningful like ws, crate, ... subcrate?

Absolutely! I started with crate but it got very repetitive and I opted for foo/bar in the interest of expediency.

I did't think it's possible to double nest workspaces in cargo?

Yes, I thought it was, but checked later and edited that bit out.

It might also be worth including a / in the example root workspace name, to point out that it could be a path.

Great idea, will do.

In my case, the target dir is specified by the [env] section to be ./target.

Hmmmm I think I'll open a different issue to read that section of the config, because it could be useful but not address it here. I don't think I'll implement it this round tho, so you may have to fiddle around with ignores even with this support :)

Edit: actually, thinking about it more, having the ignore be more intelligent than target/ is a lot more complicated even without --super, so I'll leave it as that for now and spin the whole "figure out where the target-dir actually is" thing into its own issue (#206) to be addressed later.

If --super is automatically inferred by default

Yeah I'm not super sure about doing this in the first place, actually, due to how .cargo folders can be peppered around the place without it implying this pattern. I thought it would be nice, but it's probably too prone to edge cases.


I also think Cargo Watch could help with the "xtask alias only works at the top level" problem, but I'll leave that for a future improvement that's not only scoped to this super workspace feature. (#207)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants