Skip to content

Commit dd3b70d

Browse files
committed
Auto merge of #5939 - ehuss:test-package-docs, r=alexcrichton
Add documentation for creating test dependencies. Using `Package` has always been a little unclear to me. I think I understand it now. Maybe this will help.
2 parents 676d866 + d970d05 commit dd3b70d

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

src/doc/src/reference/source-replacement.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ source, but available on the local filesystem (aka vendoring). Local registries
106106
are downloaded ahead of time, typically sync'd with a `Cargo.lock`, and are
107107
made up of a set of `*.crate` files and an index like the normal registry is.
108108

109-
The primary way to manage and crate local registry sources is through the
109+
The primary way to manage and create local registry sources is through the
110110
[`cargo-local-registry`][cargo-local-registry] subcommand, available on
111111
crates.io and can be installed with `cargo install cargo-local-registry`.
112112

tests/testsuite/support/git.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
/*
2+
# Git Testing Support
3+
4+
## Creating a git dependency
5+
`git::new()` is an easy way to create a new git repository containing a
6+
project that you can then use as a dependency. It will automatically add all
7+
the files you specify in the project and commit them to the repository.
8+
Example:
9+
10+
```
11+
let git_project = git::new("dep1", |project| {
12+
project
13+
.file("Cargo.toml", &basic_manifest("dep1"))
14+
.file("src/lib.rs", r#"pub fn f() { println!("hi!"); } "#)
15+
}).unwrap();
16+
17+
// Use the `url()` method to get the file url to the new repository.
18+
let p = project()
19+
.file("Cargo.toml", &format!(r#"
20+
[package]
21+
name = "a"
22+
version = "1.0.0"
23+
24+
[dependencies]
25+
dep1 = {{ git = '{}' }}
26+
"#, git_project.url()))
27+
.file("src/lib.rs", "extern crate dep1;")
28+
.build();
29+
```
30+
31+
## Manually creating repositories
32+
`git::repo()` can be used to create a `RepoBuilder` which provides a way of
33+
adding files to a blank repository and committing them.
34+
35+
If you want to then manipulate the repository (such as adding new files or
36+
tags), you can use `git2::Repository::open()` to open the repository and then
37+
use some of the helper functions in this file to interact with the repository.
38+
39+
*/
40+
141
use std::fs::{self, File};
242
use std::io::prelude::*;
343
use std::path::{Path, PathBuf};
@@ -16,6 +56,9 @@ pub struct RepoBuilder {
1656

1757
pub struct Repository(git2::Repository);
1858

59+
/// Create a `RepoBuilder` to build a new git repository.
60+
///
61+
/// Call `build()` to finalize and create the repository.
1962
pub fn repo(p: &Path) -> RepoBuilder {
2063
RepoBuilder::init(p)
2164
}
@@ -35,19 +78,23 @@ impl RepoBuilder {
3578
}
3679
}
3780

81+
/// Add a file to the repository.
3882
pub fn file(self, path: &str, contents: &str) -> RepoBuilder {
3983
let mut me = self.nocommit_file(path, contents);
4084
me.files.push(PathBuf::from(path));
4185
me
4286
}
4387

88+
/// Add a file that will be left in the working directory, but not added
89+
/// to the repository.
4490
pub fn nocommit_file(self, path: &str, contents: &str) -> RepoBuilder {
4591
let dst = self.repo.workdir().unwrap().join(path);
4692
t!(fs::create_dir_all(dst.parent().unwrap()));
4793
t!(t!(File::create(&dst)).write_all(contents.as_bytes()));
4894
self
4995
}
5096

97+
/// Create the repository and commit the new files.
5198
pub fn build(self) -> Repository {
5299
{
53100
let mut index = t!(self.repo.index());
@@ -80,6 +127,7 @@ impl Repository {
80127
}
81128
}
82129

130+
/// Create a new git repository with a project.
83131
pub fn new<F>(name: &str, callback: F) -> Result<Project, ProcessError>
84132
where
85133
F: FnOnce(ProjectBuilder) -> ProjectBuilder,
@@ -98,6 +146,7 @@ where
98146
Ok(git_project)
99147
}
100148

149+
/// Add all files in the working directory to the git index.
101150
pub fn add(repo: &git2::Repository) {
102151
// FIXME(libgit2/libgit2#2514): apparently add_all will add all submodules
103152
// as well, and then fail b/c they're a directory. As a stopgap, we just
@@ -121,6 +170,7 @@ pub fn add(repo: &git2::Repository) {
121170
t!(index.write());
122171
}
123172

173+
/// Add a git submodule to the repository.
124174
pub fn add_submodule<'a>(
125175
repo: &'a git2::Repository,
126176
url: &str,
@@ -137,6 +187,7 @@ pub fn add_submodule<'a>(
137187
s
138188
}
139189

190+
/// Commit changes to the git repository.
140191
pub fn commit(repo: &git2::Repository) -> git2::Oid {
141192
let tree_id = t!(t!(repo.index()).write_tree());
142193
let sig = t!(repo.signature());
@@ -155,6 +206,7 @@ pub fn commit(repo: &git2::Repository) -> git2::Oid {
155206
))
156207
}
157208

209+
/// Create a new tag in the git repository.
158210
pub fn tag(repo: &git2::Repository, name: &str) {
159211
let head = repo.head().unwrap().target().unwrap();
160212
t!(repo.tag(

tests/testsuite/support/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ let p = project()
1515
.build();
1616
```
1717
18+
If you do not specify a `Cargo.toml` manifest using `file()`, one is
19+
automatically created with a project name of `foo` using `basic_manifest()`.
20+
1821
To run cargo, call the `cargo` method and use the `hamcrest` matchers to check
1922
the output.
2023
@@ -78,6 +81,34 @@ or overwrite a binary immediately after running it. Under some conditions
7881
Windows will fail with errors like "directory not empty" or "failed to remove"
7982
or "access is denied".
8083
84+
## Specifying Dependencies
85+
86+
You should not write any tests that use the network such as contacting
87+
crates.io. Typically, simple path dependencies are the easiest way to add a
88+
dependency. Example:
89+
90+
```
91+
let p = project()
92+
.file("Cargo.toml", r#"
93+
[package]
94+
name = "foo"
95+
version = "1.0.0"
96+
97+
[dependencies]
98+
bar = {path = "bar"}
99+
"#)
100+
.file("src/lib.rs", "extern crate bar;")
101+
.file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0"))
102+
.file("bar/src/lib.rs", "")
103+
.build();
104+
```
105+
106+
If you need to test with registry dependencies, see
107+
`support::registry::Package` for creating packages you can depend on.
108+
109+
If you need to test git dependencies, see `support::git` to create a git
110+
dependency.
111+
81112
*/
82113

83114
use std::env;
@@ -530,6 +561,8 @@ impl Execs {
530561
}
531562

532563
/// Verify the exit code from the process.
564+
///
565+
/// This is not necessary if the expected exit code is `0`.
533566
pub fn with_status(mut self, expected: i32) -> Execs {
534567
self.expect_exit_code = Some(expected);
535568
self

tests/testsuite/support/registry.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,70 @@ pub fn alt_api_url() -> Url {
4949
Url::from_file_path(&*alt_api_path()).ok().unwrap()
5050
}
5151

52+
/// A builder for creating a new package in a registry.
53+
///
54+
/// This uses "source replacement" using an automatically generated
55+
/// `.cargo/config` file to ensure that dependencies will use these packages
56+
/// instead of contacting crates.io. See `source-replacement.md` for more
57+
/// details on how source replacement works.
58+
///
59+
/// Call `publish` to finalize and create the package.
60+
///
61+
/// If no files are specified, an empty `lib.rs` file is automatically created.
62+
///
63+
/// The `Cargo.toml` file is automatically generated based on the methods
64+
/// called on `Package` (for example, calling `dep()` will add to the
65+
/// `[dependencies]` automatically). You may also specify a `Cargo.toml` file
66+
/// to override the generated one.
67+
///
68+
/// This supports different registry types:
69+
/// - Regular source replacement that replaces `crates.io` (the default).
70+
/// - A "local registry" which is a subset for vendoring (see
71+
/// `Package::local`).
72+
/// - An "alternative registry" which requires specifying the registry name
73+
/// (see `Package::alternative`).
74+
///
75+
/// This does not support "directory sources". See `directory.rs` for
76+
/// `VendorPackage` which implements directory sources.
77+
///
78+
/// # Example
79+
/// ```
80+
/// // Publish package "a" depending on "b".
81+
/// Package::new("a", "1.0.0")
82+
/// .dep("b", "1.0.0")
83+
/// .file("src/lib.rs", r#"
84+
/// extern crate b;
85+
/// pub fn f() -> i32 { b::f() * 2 }
86+
/// "#)
87+
/// .publish();
88+
///
89+
/// // Publish package "b".
90+
/// Package::new("b", "1.0.0")
91+
/// .file("src/lib.rs", r#"
92+
/// pub fn f() -> i32 { 12 }
93+
/// "#)
94+
/// .publish();
95+
///
96+
/// // Create a project that uses package "a".
97+
/// let p = project()
98+
/// .file("Cargo.toml", r#"
99+
/// [package]
100+
/// name = "foo"
101+
/// version = "0.0.1"
102+
///
103+
/// [dependencies]
104+
/// a = "1.0"
105+
/// "#)
106+
/// .file("src/main.rs", r#"
107+
/// extern crate a;
108+
/// fn main() { println!("{}", a::f()); }
109+
/// "#)
110+
/// .build();
111+
///
112+
/// assert_that(
113+
/// p.cargo("run"),
114+
/// execs().with_stdout("24"));
115+
/// ```
52116
pub struct Package {
53117
name: String,
54118
vers: String,
@@ -128,6 +192,8 @@ pub fn init() {
128192
}
129193

130194
impl Package {
195+
/// Create a new package builder.
196+
/// Call `publish()` to finalize and build the package.
131197
pub fn new(name: &str, vers: &str) -> Package {
132198
init();
133199
Package {
@@ -143,47 +209,92 @@ impl Package {
143209
}
144210
}
145211

212+
/// Call with `true` to publish in a "local registry".
213+
///
214+
/// See `source-replacement.html#local-registry-sources` for more details
215+
/// on local registries. See `local_registry.rs` for the tests that use
216+
/// this.
146217
pub fn local(&mut self, local: bool) -> &mut Package {
147218
self.local = local;
148219
self
149220
}
150221

222+
/// Call with `true` to publish in an "alternative registry".
223+
///
224+
/// The name of the alternative registry is called "alternative".
225+
///
226+
/// See `unstable.html#alternate-registries` for more details on
227+
/// alternative registries. See `alt_registry.rs` for the tests that use
228+
/// this.
151229
pub fn alternative(&mut self, alternative: bool) -> &mut Package {
152230
self.alternative = alternative;
153231
self
154232
}
155233

234+
/// Add a file to the package.
156235
pub fn file(&mut self, name: &str, contents: &str) -> &mut Package {
157236
self.files.push((name.to_string(), contents.to_string()));
158237
self
159238
}
160239

240+
/// Add an "extra" file that is not rooted within the package.
241+
///
242+
/// Normal files are automatically placed within a directory named
243+
/// `$PACKAGE-$VERSION`. This allows you to override that behavior,
244+
/// typically for testing invalid behavior.
161245
pub fn extra_file(&mut self, name: &str, contents: &str) -> &mut Package {
162246
self.extra_files
163247
.push((name.to_string(), contents.to_string()));
164248
self
165249
}
166250

251+
/// Add a normal dependency. Example:
252+
/// ```
253+
/// [dependencies]
254+
/// foo = {version = "1.0"}
255+
/// ```
167256
pub fn dep(&mut self, name: &str, vers: &str) -> &mut Package {
168257
self.full_dep(name, vers, None, "normal", &[], None)
169258
}
170259

260+
/// Add a dependency with the given feature. Example:
261+
/// ```
262+
/// [dependencies]
263+
/// foo = {version = "1.0", "features": ["feat1", "feat2"]}
264+
/// ```
171265
pub fn feature_dep(&mut self, name: &str, vers: &str, features: &[&str]) -> &mut Package {
172266
self.full_dep(name, vers, None, "normal", features, None)
173267
}
174268

269+
/// Add a platform-specific dependency. Example:
270+
/// ```
271+
/// [target.'cfg(windows)'.dependencies]
272+
/// foo = {version = "1.0"}
273+
/// ```
175274
pub fn target_dep(&mut self, name: &str, vers: &str, target: &str) -> &mut Package {
176275
self.full_dep(name, vers, Some(target), "normal", &[], None)
177276
}
178277

278+
/// Add a dependency to an alternative registry.
279+
/// The given registry should be a URI to the alternative registry.
179280
pub fn registry_dep(&mut self, name: &str, vers: &str, registry: &str) -> &mut Package {
180281
self.full_dep(name, vers, None, "normal", &[], Some(registry))
181282
}
182283

284+
/// Add a dev-dependency. Example:
285+
/// ```
286+
/// [dev-dependencies]
287+
/// foo = {version = "1.0"}
288+
/// ```
183289
pub fn dev_dep(&mut self, name: &str, vers: &str) -> &mut Package {
184290
self.full_dep(name, vers, None, "dev", &[], None)
185291
}
186292

293+
/// Add a build-dependency. Example:
294+
/// ```
295+
/// [build-dependencies]
296+
/// foo = {version = "1.0"}
297+
/// ```
187298
pub fn build_dep(&mut self, name: &str, vers: &str) -> &mut Package {
188299
self.full_dep(name, vers, None, "build", &[], None)
189300
}
@@ -208,11 +319,18 @@ impl Package {
208319
self
209320
}
210321

322+
/// Specify whether or not the package is "yanked".
211323
pub fn yanked(&mut self, yanked: bool) -> &mut Package {
212324
self.yanked = yanked;
213325
self
214326
}
215327

328+
/// Create the package and place it in the registry.
329+
///
330+
/// This does not actually use Cargo's publishing system, but instead
331+
/// manually creates the entry in the registry on the filesystem.
332+
///
333+
/// Returns the checksum for the package.
216334
pub fn publish(&self) -> String {
217335
self.make_archive();
218336

@@ -358,6 +476,7 @@ impl Package {
358476
t!(ar.append(&header, contents.as_bytes()));
359477
}
360478

479+
/// Returns the path to the compressed package file.
361480
pub fn archive_dst(&self) -> PathBuf {
362481
if self.local {
363482
registry_path().join(format!("{}-{}.crate", self.name, self.vers))

0 commit comments

Comments
 (0)