Update crate_universe to allow re-pinning precise packages with pins (#2493)

This change corrects the parsing logic of `CARGO_BAZEL_REPIN` to solve
for the following issue
```
CARGO_BAZEL_REPIN=ahash@0.7.7 bazel build //...
```
```
ERROR: /home/user/Code/factory/WORKSPACE.bazel:162:12: fetching crates_repository rule //external:crates_io: Traceback (most recent call last):
	File "/home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/rules_rust/crate_universe/private/crates_repository.bzl", line 59, column 50, in _crates_repository_impl
		metadata_path = splice_workspace_manifest(
	File "/home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/rules_rust/crate_universe/private/splicing_utils.bzl", line 178, column 12, in splice_workspace_manifest
		execute(
	File "/home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/rules_rust/crate_universe/private/common_utils.bzl", line 54, column 13, in execute
		fail(_EXECUTE_ERROR_MESSAGE.format(
Error in fail: Command [/home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/crates_io/cargo-bazel, "splice", "--output-dir", /home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/crates_io/splicing-output, "--splicing-manifest", /home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/crates_io/splicing_manifest.json, "--config", /home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/crates_io/cargo-bazel.json, "--cargo", /home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/rust_linux_x86_64__x86_64-unknown-linux-gnu__stable_tools/bin/cargo, "--rustc", /home/user/.cache/bazel/_bazel_user/2a4a06230c9b85a2073801b413943939/external/rust_linux_x86_64__x86_64-unknown-linux-gnu__stable_tools/bin/rustc, "--cargo-lockfile", /home/user/Code/factory/Cargo.lock] failed with exit code 1.
STDOUT ------------------------------------------------------------------------

STDERR ------------------------------------------------------------------------

warning: unused config key `source.crates-io.index` in `/tmp/.tmpAWm8NK/.cargo/config.toml`
error: There are multiple `ahash` packages in your project, and the specification `ahash` is ambiguous.
Please re-run this command with one of the following specifications:
  ahash@0.7.7
  ahash@0.8.7

Error: Failed to update lockfile: exit status: 101
```
After this `<package_name>=<pin>` can be used to distinguish which of
the multiple versions of crates available in the lockfile should be
updated to the assigned pin.
diff --git a/crate_universe/private/crates_repository.bzl b/crate_universe/private/crates_repository.bzl
index e785343..0a3de51 100644
--- a/crate_universe/private/crates_repository.bzl
+++ b/crate_universe/private/crates_repository.bzl
@@ -125,8 +125,8 @@
 
 ```text
 [workspace]/
-    WORKSPACE
-    BUILD
+    WORKSPACE.bazel
+    BUILD.bazel
     Cargo.toml
     Cargo.Bazel.lock
     src/
@@ -183,7 +183,8 @@
 | Any of [`true`, `1`, `yes`, `on`, `workspace`] | `cargo update --workspace` |
 | Any of [`full`, `eager`, `all`] | `cargo update` |
 | `package_name` | `cargo upgrade --package package_name` |
-| `package_name@1.2.3` | `cargo upgrade --package package_name --precise 1.2.3` |
+| `package_name@1.2.3` | `cargo upgrade --package package_name@1.2.3` |
+| `package_name@1.2.3=4.5.6` | `cargo upgrade --package package_name@1.2.3 --precise=4.5.6` |
 
 If the `crates_repository` is used multiple times in the same Bazel workspace (e.g. for multiple independent
 Rust workspaces), it may additionally be useful to use the `CARGO_BAZEL_REPIN_ONLY` environment variable, which
diff --git a/crate_universe/src/metadata.rs b/crate_universe/src/metadata.rs
index 029850a..a7b5a32 100644
--- a/crate_universe/src/metadata.rs
+++ b/crate_universe/src/metadata.rs
@@ -219,7 +219,7 @@
             return Ok(Self::Workspace);
         }
 
-        let mut split = s.splitn(2, '@');
+        let mut split = s.splitn(2, '=');
         Ok(Self::Package {
             name: split.next().map(|s| s.to_owned()).unwrap(),
             version: split.next().map(|s| s.to_owned()),
@@ -707,8 +707,21 @@
         assert_eq!(
             request,
             CargoUpdateRequest::Package {
-                name: "cargo-bazel".to_owned(),
-                version: Some("1.2.3".to_owned())
+                name: "cargo-bazel@1.2.3".to_owned(),
+                version: None
+            }
+        );
+    }
+
+    #[test]
+    fn deserialize_cargo_update_request_for_precise_pin() {
+        let request = CargoUpdateRequest::from_str("cargo-bazel@1.2.3=4.5.6").unwrap();
+
+        assert_eq!(
+            request,
+            CargoUpdateRequest::Package {
+                name: "cargo-bazel@1.2.3".to_owned(),
+                version: Some("4.5.6".to_owned()),
             }
         );
     }
diff --git a/docs/crate_universe.md b/docs/crate_universe.md
index 02323db..ce5c847 100644
--- a/docs/crate_universe.md
+++ b/docs/crate_universe.md
@@ -292,8 +292,8 @@
 
 ```text
 [workspace]/
-    WORKSPACE
-    BUILD
+    WORKSPACE.bazel
+    BUILD.bazel
     Cargo.toml
     Cargo.Bazel.lock
     src/
@@ -350,7 +350,8 @@
 | Any of [`true`, `1`, `yes`, `on`, `workspace`] | `cargo update --workspace` |
 | Any of [`full`, `eager`, `all`] | `cargo update` |
 | `package_name` | `cargo upgrade --package package_name` |
-| `package_name@1.2.3` | `cargo upgrade --package package_name --precise 1.2.3` |
+| `package_name@1.2.3` | `cargo upgrade --package package_name@1.2.3` |
+| `package_name@1.2.3=4.5.6` | `cargo upgrade --package package_name@1.2.3 --precise=4.5.6` |
 
 If the `crates_repository` is used multiple times in the same Bazel workspace (e.g. for multiple independent
 Rust workspaces), it may additionally be useful to use the `CARGO_BAZEL_REPIN_ONLY` environment variable, which