blob: 923fa1ee2efff0c7bd14a59f6dbcc4ffaf3091f5 [file] [log] [blame]
Brian Silvermancc09f182022-03-09 15:40:20 -08001//! Crate specific information embedded into [crate::context::Context] objects.
2
3use std::collections::{BTreeMap, BTreeSet};
4
5use cargo_metadata::{Node, Package, PackageId};
6use serde::{Deserialize, Serialize};
7
8use crate::config::CrateId;
9use crate::metadata::{CrateAnnotation, Dependency, PairredExtras, SourceAnnotation};
10use crate::utils::sanitize_module_name;
11use crate::utils::starlark::{Glob, SelectList, SelectMap, SelectStringDict, SelectStringList};
12
13#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
14pub struct CrateDependency {
15 /// The [CrateId] of the dependency
16 pub id: CrateId,
17
18 /// The target name of the dependency. Note this may differ from the
19 /// dependency's package name in cases such as build scripts.
20 pub target: String,
21
22 /// Some dependencies are assigned aliases. This is tracked here
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub alias: Option<String>,
25}
26
27#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
28#[serde(default)]
29pub struct TargetAttributes {
30 /// The module name of the crate (notably, not the package name).
31 pub crate_name: String,
32
33 /// The path to the crate's root source file, relative to the manifest.
34 pub crate_root: Option<String>,
35
36 /// A glob pattern of all source files required by the target
37 pub srcs: Glob,
38}
39
40#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
41pub enum Rule {
42 /// `cargo_build_script`
43 BuildScript(TargetAttributes),
44
45 /// `rust_proc_macro`
46 ProcMacro(TargetAttributes),
47
48 /// `rust_library`
49 Library(TargetAttributes),
50
51 /// `rust_binary`
52 Binary(TargetAttributes),
53}
54
55/// A set of attributes common to most `rust_library`, `rust_proc_macro`, and other
56/// [core rules of `rules_rust`](https://bazelbuild.github.io/rules_rust/defs.html).
57#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
58#[serde(default)]
59pub struct CommonAttributes {
60 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
61 pub compile_data: SelectStringList,
62
63 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
64 pub compile_data_glob: BTreeSet<String>,
65
66 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
67 pub crate_features: BTreeSet<String>,
68
69 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
70 pub data: SelectStringList,
71
72 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
73 pub data_glob: BTreeSet<String>,
74
75 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
76 pub deps: SelectList<CrateDependency>,
77
78 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
79 pub extra_deps: BTreeSet<String>,
80
81 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
82 pub deps_dev: SelectList<CrateDependency>,
83
84 pub edition: String,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub linker_script: Option<String>,
88
89 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
90 pub proc_macro_deps: SelectList<CrateDependency>,
91
92 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
93 pub extra_proc_macro_deps: BTreeSet<String>,
94
95 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
96 pub proc_macro_deps_dev: SelectList<CrateDependency>,
97
98 #[serde(skip_serializing_if = "SelectStringDict::should_skip_serializing")]
99 pub rustc_env: SelectStringDict,
100
101 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
102 pub rustc_env_files: SelectStringList,
103
Brian Silverman5f6f2762022-08-13 19:30:05 -0700104 #[serde(skip_serializing_if = "Vec::is_empty")]
105 pub rustc_flags: Vec<String>,
Brian Silvermancc09f182022-03-09 15:40:20 -0800106
107 pub version: String,
108
109 #[serde(skip_serializing_if = "Vec::is_empty")]
110 pub tags: Vec<String>,
111}
112
113impl Default for CommonAttributes {
114 fn default() -> Self {
115 Self {
116 compile_data: Default::default(),
117 // Generated targets include all files in their package by default
118 compile_data_glob: BTreeSet::from(["**".to_owned()]),
119 crate_features: Default::default(),
120 data: Default::default(),
121 data_glob: Default::default(),
122 deps: Default::default(),
123 extra_deps: Default::default(),
124 deps_dev: Default::default(),
125 edition: Default::default(),
126 linker_script: Default::default(),
127 proc_macro_deps: Default::default(),
128 extra_proc_macro_deps: Default::default(),
129 proc_macro_deps_dev: Default::default(),
130 rustc_env: Default::default(),
131 rustc_env_files: Default::default(),
132 rustc_flags: Default::default(),
133 version: Default::default(),
134 tags: Default::default(),
135 }
136 }
137}
138
139// Build script attributes. See
140// https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script
141#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
142#[serde(default)]
143pub struct BuildScriptAttributes {
144 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
145 pub compile_data: SelectStringList,
146
147 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
148 pub data: SelectStringList,
149
150 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
151 pub data_glob: BTreeSet<String>,
152
153 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
154 pub deps: SelectList<CrateDependency>,
155
156 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
157 pub extra_deps: BTreeSet<String>,
158
159 #[serde(skip_serializing_if = "SelectStringDict::should_skip_serializing")]
160 pub build_script_env: SelectStringDict,
161
162 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
163 pub extra_proc_macro_deps: BTreeSet<String>,
164
165 #[serde(skip_serializing_if = "SelectList::should_skip_serializing")]
166 pub proc_macro_deps: SelectList<CrateDependency>,
167
168 #[serde(skip_serializing_if = "SelectStringDict::should_skip_serializing")]
169 pub rustc_env: SelectStringDict,
170
171 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
172 pub rustc_flags: SelectStringList,
173
174 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
175 pub rustc_env_files: SelectStringList,
176
177 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
178 pub tools: SelectStringList,
179
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub links: Option<String>,
Brian Silverman5f6f2762022-08-13 19:30:05 -0700182
183 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
184 pub toolchains: BTreeSet<String>,
Brian Silvermancc09f182022-03-09 15:40:20 -0800185}
186
187impl Default for BuildScriptAttributes {
188 fn default() -> Self {
189 Self {
190 compile_data: Default::default(),
191 data: Default::default(),
192 // Build scripts include all sources by default
193 data_glob: BTreeSet::from(["**".to_owned()]),
194 deps: Default::default(),
195 extra_deps: Default::default(),
196 build_script_env: Default::default(),
197 extra_proc_macro_deps: Default::default(),
198 proc_macro_deps: Default::default(),
199 rustc_env: Default::default(),
200 rustc_flags: Default::default(),
201 rustc_env_files: Default::default(),
202 tools: Default::default(),
203 links: Default::default(),
Brian Silverman5f6f2762022-08-13 19:30:05 -0700204 toolchains: Default::default(),
Brian Silvermancc09f182022-03-09 15:40:20 -0800205 }
206 }
207}
208
209#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
210#[serde(default)]
211pub struct CrateContext {
212 /// The package name of the current crate
213 pub name: String,
214
215 /// The full version of the current crate
216 pub version: String,
217
218 /// Optional source annotations if they were discoverable in the
219 /// lockfile. Workspace Members will not have source annotations and
220 /// potentially others.
221 pub repository: Option<SourceAnnotation>,
222
223 /// A list of all targets (lib, proc-macro, bin) associated with this package
224 pub targets: Vec<Rule>,
225
226 /// The name of the crate's root library target. This is the target that a dependent
227 /// would get if they were to depend on `{crate_name}`.
228 pub library_target_name: Option<String>,
229
230 /// A set of attributes common to most [Rule] types or target types.
231 pub common_attrs: CommonAttributes,
232
233 /// Optional attributes for build scripts. This field is only populated if
234 /// a build script (`custom-build`) target is defined for the crate.
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub build_script_attrs: Option<BuildScriptAttributes>,
237
238 /// The license used by the crate
239 pub license: Option<String>,
240
241 /// Additional text to add to the generated BUILD file.
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub additive_build_file_content: Option<String>,
244}
245
246impl CrateContext {
247 pub fn new(
248 annotation: &CrateAnnotation,
249 packages: &BTreeMap<PackageId, Package>,
250 source_annotations: &BTreeMap<PackageId, SourceAnnotation>,
251 extras: &BTreeMap<CrateId, PairredExtras>,
252 include_build_scripts: bool,
253 ) -> Self {
254 let package: &Package = &packages[&annotation.node.id];
255 let current_crate_id = CrateId::new(package.name.clone(), package.version.to_string());
256
257 let new_crate_dep = |dep: Dependency| -> CrateDependency {
258 let pkg = &packages[&dep.package_id];
259
260 // Unfortunately, The package graph and resolve graph of cargo metadata have different representations
261 // for the crate names (resolve graph sanitizes names to match module names) so to get the rest of this
262 // content to align when rendering, the dependency target needs to be explicitly sanitized.
263 let target = sanitize_module_name(&dep.target_name);
264
265 CrateDependency {
266 id: CrateId::new(pkg.name.clone(), pkg.version.to_string()),
267 target,
268 alias: dep.alias,
269 }
270 };
271
272 // Convert the dependencies into renderable strings
273 let deps = annotation.deps.normal_deps.clone().map(new_crate_dep);
274 let deps_dev = annotation.deps.normal_dev_deps.clone().map(new_crate_dep);
275 let proc_macro_deps = annotation.deps.proc_macro_deps.clone().map(new_crate_dep);
276 let proc_macro_deps_dev = annotation
277 .deps
278 .proc_macro_dev_deps
279 .clone()
280 .map(new_crate_dep);
281
282 // Gather all "common" attributes
283 let mut common_attrs = CommonAttributes {
284 crate_features: annotation.node.features.iter().cloned().collect(),
285 deps,
286 deps_dev,
287 edition: package.edition.clone(),
288 proc_macro_deps,
289 proc_macro_deps_dev,
290 version: package.version.to_string(),
291 ..Default::default()
292 };
293
294 let include_build_scripts =
295 Self::crate_includes_build_script(package, extras, include_build_scripts);
296
297 // Iterate over each target and produce a Bazel target for all supported "kinds"
298 let targets = Self::collect_targets(&annotation.node, packages, include_build_scripts);
299
300 // Parse the library crate name from the set of included targets
301 let library_target_name = {
302 let lib_targets: Vec<&TargetAttributes> = targets
303 .iter()
304 .filter_map(|t| match t {
305 Rule::ProcMacro(attrs) => Some(attrs),
306 Rule::Library(attrs) => Some(attrs),
307 _ => None,
308 })
309 .collect();
310
311 // TODO: There should only be at most 1 library target. This case
312 // should be handled in a more intelligent way.
313 assert!(lib_targets.len() <= 1);
314 lib_targets
315 .iter()
316 .last()
317 .map(|attr| attr.crate_name.clone())
318 };
319
320 // Gather any build-script related attributes
321 let build_script_target = targets.iter().find_map(|r| match r {
322 Rule::BuildScript(attr) => Some(attr),
323 _ => None,
324 });
325
326 let build_script_attrs = if let Some(target) = build_script_target {
327 // Track the build script dependency
328 common_attrs.deps.insert(
329 CrateDependency {
330 id: current_crate_id,
331 target: target.crate_name.clone(),
332 alias: None,
333 },
334 None,
335 );
336
337 let build_deps = annotation.deps.build_deps.clone().map(new_crate_dep);
338 let build_proc_macro_deps = annotation
339 .deps
340 .build_proc_macro_deps
341 .clone()
342 .map(new_crate_dep);
343
344 Some(BuildScriptAttributes {
345 deps: build_deps,
346 proc_macro_deps: build_proc_macro_deps,
347 links: package.links.clone(),
348 ..Default::default()
349 })
350 } else {
351 None
352 };
353
354 // Save the repository information for the current crate
355 let repository = source_annotations.get(&package.id).cloned();
356
357 // Identify the license type
358 let license = package.license.clone();
359
360 // Create the crate's context and apply extra settings
361 CrateContext {
362 name: package.name.clone(),
363 version: package.version.to_string(),
364 repository,
365 targets,
366 library_target_name,
367 common_attrs,
368 build_script_attrs,
369 license,
370 additive_build_file_content: None,
371 }
372 .with_overrides(extras)
373 }
374
375 fn with_overrides(mut self, extras: &BTreeMap<CrateId, PairredExtras>) -> Self {
376 let id = CrateId::new(self.name.clone(), self.version.clone());
377
378 // Insert all overrides/extras
379 if let Some(pairred_override) = extras.get(&id) {
380 let crate_extra = &pairred_override.crate_extra;
381
382 // Deps
383 if let Some(extra) = &crate_extra.deps {
384 self.common_attrs.extra_deps = extra.clone();
385 }
386
387 // Proc macro deps
388 if let Some(extra) = &crate_extra.proc_macro_deps {
389 self.common_attrs.extra_proc_macro_deps = extra.clone();
390 }
391
392 // Compile data
393 if let Some(extra) = &crate_extra.compile_data {
394 for data in extra.iter() {
395 self.common_attrs.compile_data.insert(data.clone(), None);
396 }
397 }
398
399 // Compile data glob
400 if let Some(extra) = &crate_extra.compile_data_glob {
401 self.common_attrs.compile_data_glob.extend(extra.clone());
402 }
403
404 // Crate features
405 if let Some(extra) = &crate_extra.crate_features {
406 for data in extra.iter() {
407 self.common_attrs.crate_features.insert(data.clone());
408 }
409 }
410
411 // Data
412 if let Some(extra) = &crate_extra.data {
413 for data in extra.iter() {
414 self.common_attrs.data.insert(data.clone(), None);
415 }
416 }
417
418 // Data glob
419 if let Some(extra) = &crate_extra.data_glob {
420 self.common_attrs.data_glob.extend(extra.clone());
421 }
422
423 // Rustc flags
Brian Silvermancc09f182022-03-09 15:40:20 -0800424 if let Some(extra) = &crate_extra.rustc_flags {
Brian Silverman5f6f2762022-08-13 19:30:05 -0700425 self.common_attrs.rustc_flags.append(&mut extra.clone());
Brian Silvermancc09f182022-03-09 15:40:20 -0800426 }
427
428 // Rustc env
429 if let Some(extra) = &crate_extra.rustc_env {
430 self.common_attrs.rustc_env.insert(extra.clone(), None);
431 }
432
433 // Rustc env files
434 if let Some(extra) = &crate_extra.rustc_env_files {
435 for data in extra.iter() {
436 self.common_attrs.rustc_env_files.insert(data.clone(), None);
437 }
438 }
439
440 // Build script Attributes
441 if let Some(attrs) = &mut self.build_script_attrs {
442 // Deps
443 if let Some(extra) = &crate_extra.build_script_deps {
444 attrs.extra_deps = extra.clone();
445 }
446
447 // Proc macro deps
448 if let Some(extra) = &crate_extra.build_script_proc_macro_deps {
449 attrs.extra_proc_macro_deps = extra.clone();
450 }
451
452 // Data
453 if let Some(extra) = &crate_extra.build_script_data {
454 for data in extra {
455 attrs.data.insert(data.clone(), None);
456 }
457 }
458
Brian Silverman5f6f2762022-08-13 19:30:05 -0700459 // Tools
460 if let Some(extra) = &crate_extra.build_script_tools {
461 for data in extra {
462 attrs.tools.insert(data.clone(), None);
463 }
464 }
465
466 // Toolchains
467 if let Some(extra) = &crate_extra.build_script_toolchains {
468 for data in extra {
469 attrs.toolchains.insert(data.clone());
470 }
471 }
472
Brian Silvermancc09f182022-03-09 15:40:20 -0800473 // Data glob
474 if let Some(extra) = &crate_extra.build_script_data_glob {
475 attrs.data_glob.extend(extra.clone());
476 }
477
478 // Rustc env
479 if let Some(extra) = &crate_extra.build_script_rustc_env {
480 attrs.rustc_env.insert(extra.clone(), None);
481 }
482
483 // Build script env
484 if let Some(extra) = &crate_extra.build_script_env {
485 attrs.build_script_env.insert(extra.clone(), None);
486 }
487 }
488
489 // Extra build contents
490 self.additive_build_file_content = crate_extra
491 .additive_build_file_content
492 .as_ref()
493 .map(|content| {
494 // For prettier rendering, dedent the build contents
495 textwrap::dedent(content)
496 });
497
498 // Git shallow_since
499 if let Some(SourceAnnotation::Git { shallow_since, .. }) = &mut self.repository {
500 *shallow_since = crate_extra.shallow_since.clone()
501 }
502
503 // Patch attributes
504 if let Some(repository) = &mut self.repository {
505 match repository {
506 SourceAnnotation::Git {
507 patch_args,
508 patch_tool,
509 patches,
510 ..
511 } => {
512 *patch_args = crate_extra.patch_args.clone();
513 *patch_tool = crate_extra.patch_tool.clone();
514 *patches = crate_extra.patches.clone();
515 }
516 SourceAnnotation::Http {
517 patch_args,
518 patch_tool,
519 patches,
520 ..
521 } => {
522 *patch_args = crate_extra.patch_args.clone();
523 *patch_tool = crate_extra.patch_tool.clone();
524 *patches = crate_extra.patches.clone();
525 }
526 }
527 }
528 }
529
530 self
531 }
532
533 /// Determine whether or not a crate __should__ include a build script
534 /// (build.rs) if it happens to have one.
535 fn crate_includes_build_script(
536 package: &Package,
537 overrides: &BTreeMap<CrateId, PairredExtras>,
538 default_generate_build_script: bool,
539 ) -> bool {
540 // Locate extra settings for the current package.
541 let settings = overrides
542 .iter()
543 .find(|(_, settings)| settings.package_id == package.id);
544
545 // If the crate has extra settings, which explicitly set `gen_build_script`, always use
546 // this value, otherwise, fallback to the provided default.
547 settings
548 .and_then(|(_, settings)| settings.crate_extra.gen_build_script)
549 .unwrap_or(default_generate_build_script)
550 }
551
552 /// Collect all Bazel targets that should be generated for a particular Package
553 fn collect_targets(
554 node: &Node,
555 packages: &BTreeMap<PackageId, Package>,
556 include_build_scripts: bool,
557 ) -> Vec<Rule> {
558 let package = &packages[&node.id];
559
560 let package_root = package
561 .manifest_path
562 .as_std_path()
563 .parent()
564 .expect("Every manifest should have a parent directory");
565
566 package
567 .targets
568 .iter()
569 .flat_map(|target| {
570 target
571 .kind
572 .iter()
573 .filter_map(|kind| {
574 // Unfortunately, The package graph and resolve graph of cargo metadata have different representations
575 // for the crate names (resolve graph sanitizes names to match module names) so to get the rest of this
576 // content to align when rendering, the package target names are always sanitized.
577 let crate_name = sanitize_module_name(&target.name);
578
579 // Locate the crate's root source file relative to the package root normalized for unix
Brian Silverman5f6f2762022-08-13 19:30:05 -0700580 let crate_root = pathdiff::diff_paths(&target.src_path, package_root).map(
581 // Normalize the path so that it always renders the same regardless of platform
582 |root| root.to_string_lossy().replace('\\', "/"),
583 );
Brian Silvermancc09f182022-03-09 15:40:20 -0800584
585 // Conditionally check to see if the dependencies is a build-script target
586 if include_build_scripts && kind == "custom-build" {
587 return Some(Rule::BuildScript(TargetAttributes {
588 crate_name,
589 crate_root,
590 srcs: Glob::new_rust_srcs(),
591 }));
592 }
593
594 // Check to see if the dependencies is a proc-macro target
595 if kind == "proc-macro" {
596 return Some(Rule::ProcMacro(TargetAttributes {
597 crate_name,
598 crate_root,
599 srcs: Glob::new_rust_srcs(),
600 }));
601 }
602
603 // Check to see if the dependencies is a library target
604 if ["lib", "rlib"].contains(&kind.as_str()) {
605 return Some(Rule::Library(TargetAttributes {
606 crate_name,
607 crate_root,
608 srcs: Glob::new_rust_srcs(),
609 }));
610 }
611
612 // Check to see if the dependencies is a library target
613 if kind == "bin" {
614 return Some(Rule::Binary(TargetAttributes {
615 crate_name: target.name.clone(),
616 crate_root,
617 srcs: Glob::new_rust_srcs(),
618 }));
619 }
620
621 None
622 })
623 .collect::<Vec<Rule>>()
624 })
625 .collect()
626 }
627}
628
629#[cfg(test)]
630mod test {
631 use super::*;
632
633 use crate::config::CrateAnnotations;
634 use crate::metadata::Annotations;
635
636 fn common_annotations() -> Annotations {
637 Annotations::new(
638 crate::test::metadata::common(),
639 crate::test::lockfile::common(),
640 crate::config::Config::default(),
641 )
642 .unwrap()
643 }
644
645 #[test]
646 fn new_context() {
647 let annotations = common_annotations();
648
649 let crate_annotation = &annotations.metadata.crates[&PackageId {
650 repr: "common 0.1.0 (path+file://{TEMP_DIR}/common)".to_owned(),
651 }];
652
653 let context = CrateContext::new(
654 crate_annotation,
655 &annotations.metadata.packages,
656 &annotations.lockfile.crates,
657 &annotations.pairred_extras,
658 false,
659 );
660
661 assert_eq!(context.name, "common");
662 assert_eq!(
663 context.targets,
664 vec![
665 Rule::Library(TargetAttributes {
666 crate_name: "common".to_owned(),
667 crate_root: Some("lib.rs".to_owned()),
668 srcs: Glob::new_rust_srcs(),
669 }),
670 Rule::Binary(TargetAttributes {
671 crate_name: "common-bin".to_owned(),
672 crate_root: Some("main.rs".to_owned()),
673 srcs: Glob::new_rust_srcs(),
674 }),
675 ]
676 );
677 }
678
679 #[test]
680 fn context_with_overrides() {
681 let annotations = common_annotations();
682
683 let package_id = PackageId {
684 repr: "common 0.1.0 (path+file://{TEMP_DIR}/common)".to_owned(),
685 };
686
687 let crate_annotation = &annotations.metadata.crates[&package_id];
688
689 let mut pairred_extras = BTreeMap::new();
690 pairred_extras.insert(
691 CrateId::new("common".to_owned(), "0.1.0".to_owned()),
692 PairredExtras {
693 package_id,
694 crate_extra: CrateAnnotations {
695 data_glob: Some(BTreeSet::from(["**/data_glob/**".to_owned()])),
696 ..CrateAnnotations::default()
697 },
698 },
699 );
700
701 let context = CrateContext::new(
702 crate_annotation,
703 &annotations.metadata.packages,
704 &annotations.lockfile.crates,
705 &pairred_extras,
706 false,
707 );
708
709 assert_eq!(context.name, "common");
710 assert_eq!(
711 context.targets,
712 vec![
713 Rule::Library(TargetAttributes {
714 crate_name: "common".to_owned(),
715 crate_root: Some("lib.rs".to_owned()),
716 srcs: Glob::new_rust_srcs(),
717 }),
718 Rule::Binary(TargetAttributes {
719 crate_name: "common-bin".to_owned(),
720 crate_root: Some("main.rs".to_owned()),
721 srcs: Glob::new_rust_srcs(),
722 }),
723 ]
724 );
725 assert_eq!(
726 context.common_attrs.data_glob,
727 BTreeSet::from(["**/data_glob/**".to_owned()])
728 );
729 }
730
731 fn build_script_annotations() -> Annotations {
732 Annotations::new(
733 crate::test::metadata::build_scripts(),
734 crate::test::lockfile::build_scripts(),
735 crate::config::Config::default(),
736 )
737 .unwrap()
738 }
739
740 fn crate_type_annotations() -> Annotations {
741 Annotations::new(
742 crate::test::metadata::crate_types(),
743 crate::test::lockfile::crate_types(),
744 crate::config::Config::default(),
745 )
746 .unwrap()
747 }
748
749 #[test]
750 fn context_with_build_script() {
751 let annotations = build_script_annotations();
752
753 let package_id = PackageId {
754 repr: "openssl-sys 0.9.72 (registry+https://github.com/rust-lang/crates.io-index)"
755 .to_owned(),
756 };
757
758 let crate_annotation = &annotations.metadata.crates[&package_id];
759
760 let context = CrateContext::new(
761 crate_annotation,
762 &annotations.metadata.packages,
763 &annotations.lockfile.crates,
764 &annotations.pairred_extras,
765 true,
766 );
767
768 assert_eq!(context.name, "openssl-sys");
769 assert!(context.build_script_attrs.is_some());
770 assert_eq!(
771 context.targets,
772 vec![
773 Rule::Library(TargetAttributes {
774 crate_name: "openssl_sys".to_owned(),
775 crate_root: Some("src/lib.rs".to_owned()),
776 srcs: Glob::new_rust_srcs(),
777 }),
778 Rule::BuildScript(TargetAttributes {
779 crate_name: "build_script_main".to_owned(),
780 crate_root: Some("build/main.rs".to_owned()),
781 srcs: Glob::new_rust_srcs(),
782 })
783 ]
784 );
785
786 // Cargo build scripts should include all sources
787 assert!(context.build_script_attrs.unwrap().data_glob.contains("**"));
788 }
789
790 #[test]
791 fn context_disabled_build_script() {
792 let annotations = build_script_annotations();
793
794 let package_id = PackageId {
795 repr: "openssl-sys 0.9.72 (registry+https://github.com/rust-lang/crates.io-index)"
796 .to_owned(),
797 };
798
799 let crate_annotation = &annotations.metadata.crates[&package_id];
800
801 let context = CrateContext::new(
802 crate_annotation,
803 &annotations.metadata.packages,
804 &annotations.lockfile.crates,
805 &annotations.pairred_extras,
806 false,
807 );
808
809 assert_eq!(context.name, "openssl-sys");
810 assert!(context.build_script_attrs.is_none());
811 assert_eq!(
812 context.targets,
813 vec![Rule::Library(TargetAttributes {
814 crate_name: "openssl_sys".to_owned(),
815 crate_root: Some("src/lib.rs".to_owned()),
816 srcs: Glob::new_rust_srcs(),
817 })],
818 );
819 }
820
821 #[test]
822 fn context_rlib_crate_type() {
823 let annotations = crate_type_annotations();
824
825 let package_id = PackageId {
826 repr: "sysinfo 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)"
827 .to_owned(),
828 };
829
830 let crate_annotation = &annotations.metadata.crates[&package_id];
831
832 let context = CrateContext::new(
833 crate_annotation,
834 &annotations.metadata.packages,
835 &annotations.lockfile.crates,
836 &annotations.pairred_extras,
837 false,
838 );
839
840 assert_eq!(context.name, "sysinfo");
841 assert!(context.build_script_attrs.is_none());
842 assert_eq!(
843 context.targets,
844 vec![Rule::Library(TargetAttributes {
845 crate_name: "sysinfo".to_owned(),
846 crate_root: Some("src/lib.rs".to_owned()),
847 srcs: Glob::new_rust_srcs(),
848 })],
849 );
850 }
851}