Cargo.toml override / includes?

I'm developing several crates in parallel, in separate source control repositories. I'd like to have a semi-permanent [patch] section for development that points to my local working copies. That configuration isn't much use to anyone else, though, so I don't want it in the commits that I push to the public repositories. Is there a way to put this section in its own file and set up my local cargo configuration to splice it in?

1 Like

You can combine path with a version number ot a git dependency.

my_crate = { version = "0.1", path = "local/path/to/my_crate" }

This will try to use the path first then from crates.io if the path doesn't work. You can replace the version number with a git path if you need to.

1 Like

Thanks. That's not ideal in that it pollutes the repository with my local directory structure, but maybe I can make something reasonable happen with symlinks that are in .gitignore.

That's true, I mosty see this used in workspaces, where the local directory structure is visible. Not sure how to hide that.

I just tried to do this and got a warning:

warning: dependency (typenum-uuid) specification is ambiguous. Only one of `git` or `path` is allowed. This will be considered an error in future versions
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s

Cargo.toml section:

[dependencies.typenum-uuid]
git = "https://2-71828.com/git/typenum-uuid"
branch = "dev"
path = "local-dev/typenum-uuid"

Oh, I though git worked with path, looks like I misremembered. In that case, I'm not sure how to solve this

I think the only way of overriding dependencies without modifying Cargo.toml is the paths key in .cargo/config.toml. Unfortunately, this does not work with git dependencies either. (It also has other limitations that make it unusable for many workflows.)

1 Like

The [patch] documentation is a bit vague about what it actually does. I doubt it's using the patch command, but there's an implication that it might somehow combine the two source directories. If it's pointed at an empty directory, will it use the original source unchanged?

Otherwise, I'm tempted to check in a Cargo.toml.m4 file instead to get some custom configuration options. Hopefully someone can come up with something better.

[patch] has nothing to do with diff/patch. It's an upgrade of an earlier design of the [replace] section, so the better name was already taken :slight_smile:

[patch.'http://git.repo.url'] crate_name = { path = "" } can be used to replace git deps.

Right. My question is what does the verb "patch" mean when it's used in the Cargo Book; it's never actually defined, and is used extensively in the [patch] documentation: (emphasis mine)

Each entry in these tables is a normal dependency specification, the same as found in the [dependencies] section of the manifest. The dependencies listed in the [patch] section are resolved and used to patch the source at the URL specified. The above manifest snippet patches the crates-io source (e.g. crates.io itself) with the foo crate and bar crate. It also patches the https://github.com/example/baz source with a my-branch that comes from elsewhere.

Sources can be patched with versions of crates that do not exist, and they can also be patched with versions of crates that already exist. If a source is patched with a crate version that already exists in the source, then the source's original crate is replaced.

In particular, my goal is to have an override that's conditioned on something that's not checked into source control. What happens if the patch.'git_repo_url'.crate_name.path key points to an empty or nonexistent directory; does cargo apply a null patch (and thus use the original sources unchanged)?

If so, I can have a [patch] section that points at an ignored directory inside this repository, and put symlinks there to my other local repositories. Anyone that isn't working on one of the other repositories will have an empty directory there and thus Cargo will clone the dependency's public repository.

In Cargo patch means replace. Instead of using original definition of a dependency, it uses the one you provide.

If you provide a path to non-existent directory, that will be an error. The same way as if you set wrong dir in [dependencies].

The patch section has to be in Cargo.toml, unfortunately. If you're dealing with a single crate, then a hack is to create a Cargo Workspace in a parent directory. [patch] section is per workspace, not per crate. However, workspaces can't be nested, so if you already have a workspace you will need to change the existing Cargo.toml.

Even if you have to modify existing Cargo.toml, [patch] makes it slightly easier, because you can get away with just appending to the file. You only need to change one file to replace deps everywhere in the entire dependency tree.

1 Like