Rust project fails to build

I made this static-site generator, Mandy, that depends on my crate coutils. Coutils recently got an update that separated functionality into features so that coutils could be used with projects that would be built with WASM or MUSL. This update is version 1.6.0. The latest stable version of Mandy depends on Coutils v.1.5.0. Recently I tried to install Mandy directly from source with Cargo and got the following error. I tried debugging but I'm quite stuck and unsure what could have caused this. I know Coutils caused this but I can't figure out how and why. Any advice on how to fix this would be much appreciated. Here's the build log for Mandy:

cargo install --git https://github.com/angeldollface/mandy.git mandy-bin --tag v.0.3.4
    Updating git repository `https://github.com/angeldollface/mandy.git`
  Installing mandy-bin v0.3.4 (https://github.com/angeldollface/mandy.git?tag=v.0.3.4#b85b005c)
    Updating crates.io index
  Downloaded either v1.11.0
  Downloaded jobserver v0.1.30
  Downloaded winnow v0.6.6
  Downloaded time v0.3.36
  Downloaded 4 crates (325.8 KB) in 1.53s
   Compiling proc-macro2 v1.0.79
   Compiling unicode-ident v1.0.12
   Compiling libc v0.2.153
   Compiling version_check v0.9.4
   Compiling serde v1.0.197
   Compiling autocfg v1.2.0
   Compiling pkg-config v0.3.30
   Compiling quote v1.0.36
   Compiling jobserver v0.1.30
   Compiling thiserror v1.0.58
   Compiling syn v2.0.58
   Compiling cc v1.0.92
   Compiling cfg-if v1.0.0
   Compiling vcpkg v0.2.15
   Compiling memchr v2.7.2
   Compiling num-traits v0.2.18
   Compiling unicase v2.7.0
   Compiling ucd-trie v0.1.6
   Compiling aho-corasick v1.1.3
   Compiling openssl-sys v0.9.102
   Compiling libz-sys v1.1.16
   Compiling getrandom v0.2.14
   Compiling once_cell v1.19.0
   Compiling regex-syntax v0.8.3
   Compiling percent-encoding v2.3.1
   Compiling itoa v1.0.11
   Compiling rand_core v0.6.4
   Compiling serde_derive v1.0.197
   Compiling thiserror-impl v1.0.58
   Compiling regex-automata v0.4.6
   Compiling pest v2.7.9
   Compiling time-core v0.1.2
   Compiling siphasher v0.3.11
   Compiling powerfmt v0.2.0
   Compiling num-conv v0.1.0
   Compiling either v1.11.0
   Compiling ppv-lite86 v0.2.17
   Compiling pest_meta v2.7.9
   Compiling rand_chacha v0.3.1
   Compiling pest_generator v2.7.9
   Compiling regex v1.10.4
   Compiling time-macros v0.2.18
   Compiling deranged v0.3.11
   Compiling phf_shared v0.11.2
   Compiling rand v0.8.5
   Compiling libssh2-sys v0.3.0
   Compiling hashbrown v0.14.3
   Compiling tinyvec_macros v0.1.1
   Compiling static_assertions v1.1.0
   Compiling equivalent v1.0.1
   Compiling time v0.3.36
   Compiling kstring v2.0.0
   Compiling tinyvec v1.6.0
   Compiling indexmap v2.2.6
   Compiling phf_generator v0.11.2
   Compiling pest_derive v2.7.9
   Compiling itertools v0.10.5
   Compiling liquid-derive v0.26.4
   Compiling ahash v0.8.11
   Compiling ryu v1.0.17
   Compiling anymap2 v0.13.0
   Compiling doc-comment v0.3.3
   Compiling phf_macros v0.11.2
   Compiling mime_guess v2.0.4
   Compiling liquid-core v0.26.4
   Compiling unicode-normalization v0.1.23
   Compiling libgit2-sys v0.15.2+1.6.4
   Compiling indexmap v1.9.3
   Compiling unicode-bidi v0.3.15
   Compiling unicode-segmentation v1.11.0
   Compiling zerocopy v0.7.32
   Compiling log v0.4.21
   Compiling liquid-lib v0.26.4
   Compiling idna v0.5.0
   Compiling phf v0.11.2
   Compiling coutils v1.6.0
   Compiling form_urlencoded v1.2.1
   Compiling ascii v1.1.0
   Compiling mime v0.3.17
   Compiling linked-hash-map v0.5.6
   Compiling chunked_transfer v1.5.0
   Compiling httpdate v1.0.3
   Compiling hashbrown v0.12.3
   Compiling serde_json v1.0.115
   Compiling tiny_http v0.12.0
   Compiling yaml-rust v0.4.5
   Compiling url v2.5.0
   Compiling liquid v0.26.4
   Compiling hashbrown v0.13.2
   Compiling toml_datetime v0.6.5
   Compiling serde_spanned v0.6.5
   Compiling merrors v0.1.0 ($HOME/.cargo/git/checkouts/mandy-b448de8024baed71/b85b005/components/merrors)
   Compiling winnow v0.6.6
   Compiling openssl-probe v0.1.5
   Compiling bitflags v1.3.2
   Compiling iana-time-zone v0.1.60
   Compiling lasso v0.7.2
   Compiling chrono v0.4.37
   Compiling context v0.1.0 ($HOME/.cargo/git/checkouts/mandy-b448de8024baed71/b85b005/components/context)
   Compiling file-serve v0.2.4
   Compiling serde_yaml v0.8.26
   Compiling toml_edit v0.22.9
   Compiling emojis v0.6.1
   Compiling colorize v0.1.0
   Compiling lazy_static v1.4.0
   Compiling pipeline v0.5.0
   Compiling codemap v0.1.3
   Compiling unsafe-libyaml v0.2.11
   Compiling grass_compiler v0.13.2
   Compiling serde_yaml v0.9.34+deprecated
   Compiling markdown v0.3.0
   Compiling toml v0.8.12
   Compiling yaml-front-matter v0.1.0
   Compiling itertools v0.12.1
   Compiling processors v0.1.0 ($HOME/.cargo/git/checkouts/mandy-b448de8024baed71/b85b005/components/processors)
error[E0432]: unresolved import `coutils::Entity`
  --> components/processors/src/modules/data.rs:14:5
   |
14 | use coutils::Entity;
   |     ^^^^^^^^^^^^^^^ no `Entity` in the root

error[E0432]: unresolved import `coutils::read_file`
  --> components/processors/src/modules/data.rs:19:5
   |
19 | use coutils::read_file;
   |     ^^^^^^^^^^^^^^^^^^ no `read_file` in the root

error[E0432]: unresolved import `coutils::FileEntry`
  --> components/processors/src/modules/data.rs:23:5
   |
23 | use coutils::FileEntry;
   |     ^^^^^^^^^^^^^^^^^^ no `FileEntry` in the root

error[E0432]: unresolved import `coutils::list_dir_contents`
  --> components/processors/src/modules/data.rs:47:5
   |
47 | use coutils::list_dir_contents;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `list_dir_contents` in the root

For more information about this error, try `rustc --explain E0432`.
error: could not compile `processors` (lib) due to 4 previous errors
warning: build failed, waiting for other jobs to finish...
error: failed to compile `mandy-bin v0.3.4 (https://github.com/angeldollface/mandy.git?tag=v.0.3.4#b85b005c)`, intermediate artifacts can be found at `/tmp/cargo-installGBUSOq`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

I should add that I'm on Arch Linux 6.8.5 with Rust and Cargo 1.77.2. Tried the same thing on the latest Mac OS and that failed for the same reason.

Well, 1.6.0 needs to be a compatible upgrade for any crate using 1.5.0, so Cargo upgraded to it automatically, as it is supposed to. However, you introduced optional features that gate the functionality you're trying to use, and didn't enable them by default.

Basically: you broke your promise to Cargo that 1.6 was compatible with 1.5, and as a result, you will have broken every downstream user of coutils that depended on the functionality that is now feature-gated.

When you make a breaking change in a crate, you are expected to bump the major version (such as to 2.x in this case). If you don't, well, now you know what can happen. :slight_smile:

Edit: here's more about Cargo's semver policy.

2 Likes

Hmm, I understand, thank you for explaining this so clearly, is there a way to force Cargo to use 1.5?

There is, but you should only use it as a temporary stop-gap measure. The correct course of action is to fix coutils by yanking the incompatible version(s), publishing a new compatible version if necessary, and then optionally re-publishing your breaking changes with a new major version.

To force Cargo to not use the incompatible version, you will want to read through Cargo's documentation on specifying dependencies. In particular, you will probably want something like 1.5, <1.6. Do note, however, that Cargo explicitly warns against doing this:

Avoid constraining the upper bound of a version to be anything less than the next semver incompatible version (e.g. avoid ">=2.0, <2.4") as other packages in the dependency tree may require a newer version, leading to an unresolvable error (see #9029).

(Because this is a semver break, there isn't really a good way of doing this. As I said, the best thing to do is just fix coutils.)

4 Likes

Hi Daniel, so I yanked v.1.6. Build succeeds now. If in the next version of Mandy I were to use the gated version of coutils under say 2.0, would thatbreak Mandy versions that rely on 1.5?

clippy can make a whole lot of suggestions to how to improve your code. try running cargo clippy.

You can also spend some time checking functionality available in the standard library - most of your helpers are not really needed.

For example this

pub fn has_item<T: Clone + PartialEq>(
    subject: &Vec<T>, 
    item: &T
) -> bool {
    let mut result: bool = false;
    let match_op = &subject.iter().position(|r| r == item);
    match match_op {
        Some(_x) => {
            result = true;
        }
        None => {}
    }
    return result;
}

Is the same as this

subject.contains(item)

Or this

/// Gets the last item of a string array and returns it.
pub fn get_last_item<T: Debug + Clone + PartialEq>(
    arr: &Vec<T>
) -> T {
    let array_length: usize = arr.len();
    let last_item_index: usize = array_length -1;
    return arr[last_item_index].clone();
}

is

arr.last().unwrap().clone()
1 Like

:+1:

If someone is depending on coutils = "1.5", then 2.0 would be considered incompatible, and Cargo won't use it. The only reason it would use it is if someone has written something like coutils = ">=1.5". However, if someone does that, they are explicitly opting in to accepting potentially breaking changes, and that means it's their problem, not yours. :slight_smile:

2 Likes

FYI: there's a tool, cargo semver-checks, that you can use to check your changes against past versions, and warn you of some SemVer rule breaks. It aims to not have false positives, but as a result can have false negatives.

@DanielKeep Thank you so much for your help, I'm gonna publish 2.0 soon! @farnz Hmm might be useful, I'm gonna look into this! Thank you very much.

1 Like

@manpacket Well, a lot of my other projects use coutils as a base so I don't think that really helps. :woman_shrugging:

You can start using clippy right now regardless - it can help to improve your other project as well as coutils. Then as you work on other projects - you can start removing helpers in favor of standard library implementations, will only get faster/more reliable after that. Once nothing uses this particular helper - you can remove it. It might take some time.

2 Likes

I could, but I won't.

I did not mean to sound hostile but coutils is the way it is for two very important reasons:

  • I wrote the library when I was just learning Rust 2-3 years ago and the whole error-handling paradigm Rust used was quite alien to me. I wanted functions which would allow me to check if an operation passed or not using booleans. Obviously now I know this can be done via ".is_ok()". I did not know it then, however.

  • I maintain a lot of projects that rely on coutils and have a lot of other stuff going on, doing what you suggested would take a lot of time and effort that I do not really have the strength for at this point in time.

Thank you for your suggestions all the same, though.

I did actually start using clippy and removed a lot of utility functions that had std-lib implementations in this library.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.