blob: 0278ebeb60e0386bbfc8c19ad26b3d92065a3eba [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
104 #[serde(skip_serializing_if = "SelectStringList::should_skip_serializing")]
105 pub rustc_flags: SelectStringList,
106
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>,
182}
183
184impl Default for BuildScriptAttributes {
185 fn default() -> Self {
186 Self {
187 compile_data: Default::default(),
188 data: Default::default(),
189 // Build scripts include all sources by default
190 data_glob: BTreeSet::from(["**".to_owned()]),
191 deps: Default::default(),
192 extra_deps: Default::default(),
193 build_script_env: Default::default(),
194 extra_proc_macro_deps: Default::default(),
195 proc_macro_deps: Default::default(),
196 rustc_env: Default::default(),
197 rustc_flags: Default::default(),
198 rustc_env_files: Default::default(),
199 tools: Default::default(),
200 links: Default::default(),
201 }
202 }
203}
204
205#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
206#[serde(default)]
207pub struct CrateContext {
208 /// The package name of the current crate
209 pub name: String,
210
211 /// The full version of the current crate
212 pub version: String,
213
214 /// Optional source annotations if they were discoverable in the
215 /// lockfile. Workspace Members will not have source annotations and
216 /// potentially others.
217 pub repository: Option<SourceAnnotation>,
218
219 /// A list of all targets (lib, proc-macro, bin) associated with this package
220 pub targets: Vec<Rule>,
221
222 /// The name of the crate's root library target. This is the target that a dependent
223 /// would get if they were to depend on `{crate_name}`.
224 pub library_target_name: Option<String>,
225
226 /// A set of attributes common to most [Rule] types or target types.
227 pub common_attrs: CommonAttributes,
228
229 /// Optional attributes for build scripts. This field is only populated if
230 /// a build script (`custom-build`) target is defined for the crate.
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub build_script_attrs: Option<BuildScriptAttributes>,
233
234 /// The license used by the crate
235 pub license: Option<String>,
236
237 /// Additional text to add to the generated BUILD file.
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub additive_build_file_content: Option<String>,
240}
241
242impl CrateContext {
243 pub fn new(
244 annotation: &CrateAnnotation,
245 packages: &BTreeMap<PackageId, Package>,
246 source_annotations: &BTreeMap<PackageId, SourceAnnotation>,
247 extras: &BTreeMap<CrateId, PairredExtras>,
248 include_build_scripts: bool,
249 ) -> Self {
250 let package: &Package = &packages[&annotation.node.id];
251 let current_crate_id = CrateId::new(package.name.clone(), package.version.to_string());
252
253 let new_crate_dep = |dep: Dependency| -> CrateDependency {
254 let pkg = &packages[&dep.package_id];
255
256 // Unfortunately, The package graph and resolve graph of cargo metadata have different representations
257 // for the crate names (resolve graph sanitizes names to match module names) so to get the rest of this
258 // content to align when rendering, the dependency target needs to be explicitly sanitized.
259 let target = sanitize_module_name(&dep.target_name);
260
261 CrateDependency {
262 id: CrateId::new(pkg.name.clone(), pkg.version.to_string()),
263 target,
264 alias: dep.alias,
265 }
266 };
267
268 // Convert the dependencies into renderable strings
269 let deps = annotation.deps.normal_deps.clone().map(new_crate_dep);
270 let deps_dev = annotation.deps.normal_dev_deps.clone().map(new_crate_dep);
271 let proc_macro_deps = annotation.deps.proc_macro_deps.clone().map(new_crate_dep);
272 let proc_macro_deps_dev = annotation
273 .deps
274 .proc_macro_dev_deps
275 .clone()
276 .map(new_crate_dep);
277
278 // Gather all "common" attributes
279 let mut common_attrs = CommonAttributes {
280 crate_features: annotation.node.features.iter().cloned().collect(),
281 deps,
282 deps_dev,
283 edition: package.edition.clone(),
284 proc_macro_deps,
285 proc_macro_deps_dev,
286 version: package.version.to_string(),
287 ..Default::default()
288 };
289
290 let include_build_scripts =
291 Self::crate_includes_build_script(package, extras, include_build_scripts);
292
293 // Iterate over each target and produce a Bazel target for all supported "kinds"
294 let targets = Self::collect_targets(&annotation.node, packages, include_build_scripts);
295
296 // Parse the library crate name from the set of included targets
297 let library_target_name = {
298 let lib_targets: Vec<&TargetAttributes> = targets
299 .iter()
300 .filter_map(|t| match t {
301 Rule::ProcMacro(attrs) => Some(attrs),
302 Rule::Library(attrs) => Some(attrs),
303 _ => None,
304 })
305 .collect();
306
307 // TODO: There should only be at most 1 library target. This case
308 // should be handled in a more intelligent way.
309 assert!(lib_targets.len() <= 1);
310 lib_targets
311 .iter()
312 .last()
313 .map(|attr| attr.crate_name.clone())
314 };
315
316 // Gather any build-script related attributes
317 let build_script_target = targets.iter().find_map(|r| match r {
318 Rule::BuildScript(attr) => Some(attr),
319 _ => None,
320 });
321
322 let build_script_attrs = if let Some(target) = build_script_target {
323 // Track the build script dependency
324 common_attrs.deps.insert(
325 CrateDependency {
326 id: current_crate_id,
327 target: target.crate_name.clone(),
328 alias: None,
329 },
330 None,
331 );
332
333 let build_deps = annotation.deps.build_deps.clone().map(new_crate_dep);
334 let build_proc_macro_deps = annotation
335 .deps
336 .build_proc_macro_deps
337 .clone()
338 .map(new_crate_dep);
339
340 Some(BuildScriptAttributes {
341 deps: build_deps,
342 proc_macro_deps: build_proc_macro_deps,
343 links: package.links.clone(),
344 ..Default::default()
345 })
346 } else {
347 None
348 };
349
350 // Save the repository information for the current crate
351 let repository = source_annotations.get(&package.id).cloned();
352
353 // Identify the license type
354 let license = package.license.clone();
355
356 // Create the crate's context and apply extra settings
357 CrateContext {
358 name: package.name.clone(),
359 version: package.version.to_string(),
360 repository,
361 targets,
362 library_target_name,
363 common_attrs,
364 build_script_attrs,
365 license,
366 additive_build_file_content: None,
367 }
368 .with_overrides(extras)
369 }
370
371 fn with_overrides(mut self, extras: &BTreeMap<CrateId, PairredExtras>) -> Self {
372 let id = CrateId::new(self.name.clone(), self.version.clone());
373
374 // Insert all overrides/extras
375 if let Some(pairred_override) = extras.get(&id) {
376 let crate_extra = &pairred_override.crate_extra;
377
378 // Deps
379 if let Some(extra) = &crate_extra.deps {
380 self.common_attrs.extra_deps = extra.clone();
381 }
382
383 // Proc macro deps
384 if let Some(extra) = &crate_extra.proc_macro_deps {
385 self.common_attrs.extra_proc_macro_deps = extra.clone();
386 }
387
388 // Compile data
389 if let Some(extra) = &crate_extra.compile_data {
390 for data in extra.iter() {
391 self.common_attrs.compile_data.insert(data.clone(), None);
392 }
393 }
394
395 // Compile data glob
396 if let Some(extra) = &crate_extra.compile_data_glob {
397 self.common_attrs.compile_data_glob.extend(extra.clone());
398 }
399
400 // Crate features
401 if let Some(extra) = &crate_extra.crate_features {
402 for data in extra.iter() {
403 self.common_attrs.crate_features.insert(data.clone());
404 }
405 }
406
407 // Data
408 if let Some(extra) = &crate_extra.data {
409 for data in extra.iter() {
410 self.common_attrs.data.insert(data.clone(), None);
411 }
412 }
413
414 // Data glob
415 if let Some(extra) = &crate_extra.data_glob {
416 self.common_attrs.data_glob.extend(extra.clone());
417 }
418
419 // Rustc flags
420 // TODO: SelectList is currently backed by `BTreeSet` which is generally incorrect
421 // for rustc flags. Should SelectList be refactored?
422 if let Some(extra) = &crate_extra.rustc_flags {
423 for data in extra.iter() {
424 self.common_attrs.rustc_flags.insert(data.clone(), None);
425 }
426 }
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
459 // Data glob
460 if let Some(extra) = &crate_extra.build_script_data_glob {
461 attrs.data_glob.extend(extra.clone());
462 }
463
464 // Rustc env
465 if let Some(extra) = &crate_extra.build_script_rustc_env {
466 attrs.rustc_env.insert(extra.clone(), None);
467 }
468
469 // Build script env
470 if let Some(extra) = &crate_extra.build_script_env {
471 attrs.build_script_env.insert(extra.clone(), None);
472 }
473 }
474
475 // Extra build contents
476 self.additive_build_file_content = crate_extra
477 .additive_build_file_content
478 .as_ref()
479 .map(|content| {
480 // For prettier rendering, dedent the build contents
481 textwrap::dedent(content)
482 });
483
484 // Git shallow_since
485 if let Some(SourceAnnotation::Git { shallow_since, .. }) = &mut self.repository {
486 *shallow_since = crate_extra.shallow_since.clone()
487 }
488
489 // Patch attributes
490 if let Some(repository) = &mut self.repository {
491 match repository {
492 SourceAnnotation::Git {
493 patch_args,
494 patch_tool,
495 patches,
496 ..
497 } => {
498 *patch_args = crate_extra.patch_args.clone();
499 *patch_tool = crate_extra.patch_tool.clone();
500 *patches = crate_extra.patches.clone();
501 }
502 SourceAnnotation::Http {
503 patch_args,
504 patch_tool,
505 patches,
506 ..
507 } => {
508 *patch_args = crate_extra.patch_args.clone();
509 *patch_tool = crate_extra.patch_tool.clone();
510 *patches = crate_extra.patches.clone();
511 }
512 }
513 }
514 }
515
516 self
517 }
518
519 /// Determine whether or not a crate __should__ include a build script
520 /// (build.rs) if it happens to have one.
521 fn crate_includes_build_script(
522 package: &Package,
523 overrides: &BTreeMap<CrateId, PairredExtras>,
524 default_generate_build_script: bool,
525 ) -> bool {
526 // Locate extra settings for the current package.
527 let settings = overrides
528 .iter()
529 .find(|(_, settings)| settings.package_id == package.id);
530
531 // If the crate has extra settings, which explicitly set `gen_build_script`, always use
532 // this value, otherwise, fallback to the provided default.
533 settings
534 .and_then(|(_, settings)| settings.crate_extra.gen_build_script)
535 .unwrap_or(default_generate_build_script)
536 }
537
538 /// Collect all Bazel targets that should be generated for a particular Package
539 fn collect_targets(
540 node: &Node,
541 packages: &BTreeMap<PackageId, Package>,
542 include_build_scripts: bool,
543 ) -> Vec<Rule> {
544 let package = &packages[&node.id];
545
546 let package_root = package
547 .manifest_path
548 .as_std_path()
549 .parent()
550 .expect("Every manifest should have a parent directory");
551
552 package
553 .targets
554 .iter()
555 .flat_map(|target| {
556 target
557 .kind
558 .iter()
559 .filter_map(|kind| {
560 // Unfortunately, The package graph and resolve graph of cargo metadata have different representations
561 // for the crate names (resolve graph sanitizes names to match module names) so to get the rest of this
562 // content to align when rendering, the package target names are always sanitized.
563 let crate_name = sanitize_module_name(&target.name);
564
565 // Locate the crate's root source file relative to the package root normalized for unix
566 let crate_root =
567 pathdiff::diff_paths(target.src_path.to_string(), package_root).map(
568 // Normalize the path so that it always renders the same regardless of platform
569 |root| root.to_string_lossy().replace("\\", "/"),
570 );
571
572 // Conditionally check to see if the dependencies is a build-script target
573 if include_build_scripts && kind == "custom-build" {
574 return Some(Rule::BuildScript(TargetAttributes {
575 crate_name,
576 crate_root,
577 srcs: Glob::new_rust_srcs(),
578 }));
579 }
580
581 // Check to see if the dependencies is a proc-macro target
582 if kind == "proc-macro" {
583 return Some(Rule::ProcMacro(TargetAttributes {
584 crate_name,
585 crate_root,
586 srcs: Glob::new_rust_srcs(),
587 }));
588 }
589
590 // Check to see if the dependencies is a library target
591 if ["lib", "rlib"].contains(&kind.as_str()) {
592 return Some(Rule::Library(TargetAttributes {
593 crate_name,
594 crate_root,
595 srcs: Glob::new_rust_srcs(),
596 }));
597 }
598
599 // Check to see if the dependencies is a library target
600 if kind == "bin" {
601 return Some(Rule::Binary(TargetAttributes {
602 crate_name: target.name.clone(),
603 crate_root,
604 srcs: Glob::new_rust_srcs(),
605 }));
606 }
607
608 None
609 })
610 .collect::<Vec<Rule>>()
611 })
612 .collect()
613 }
614}
615
616#[cfg(test)]
617mod test {
618 use super::*;
619
620 use crate::config::CrateAnnotations;
621 use crate::metadata::Annotations;
622
623 fn common_annotations() -> Annotations {
624 Annotations::new(
625 crate::test::metadata::common(),
626 crate::test::lockfile::common(),
627 crate::config::Config::default(),
628 )
629 .unwrap()
630 }
631
632 #[test]
633 fn new_context() {
634 let annotations = common_annotations();
635
636 let crate_annotation = &annotations.metadata.crates[&PackageId {
637 repr: "common 0.1.0 (path+file://{TEMP_DIR}/common)".to_owned(),
638 }];
639
640 let context = CrateContext::new(
641 crate_annotation,
642 &annotations.metadata.packages,
643 &annotations.lockfile.crates,
644 &annotations.pairred_extras,
645 false,
646 );
647
648 assert_eq!(context.name, "common");
649 assert_eq!(
650 context.targets,
651 vec![
652 Rule::Library(TargetAttributes {
653 crate_name: "common".to_owned(),
654 crate_root: Some("lib.rs".to_owned()),
655 srcs: Glob::new_rust_srcs(),
656 }),
657 Rule::Binary(TargetAttributes {
658 crate_name: "common-bin".to_owned(),
659 crate_root: Some("main.rs".to_owned()),
660 srcs: Glob::new_rust_srcs(),
661 }),
662 ]
663 );
664 }
665
666 #[test]
667 fn context_with_overrides() {
668 let annotations = common_annotations();
669
670 let package_id = PackageId {
671 repr: "common 0.1.0 (path+file://{TEMP_DIR}/common)".to_owned(),
672 };
673
674 let crate_annotation = &annotations.metadata.crates[&package_id];
675
676 let mut pairred_extras = BTreeMap::new();
677 pairred_extras.insert(
678 CrateId::new("common".to_owned(), "0.1.0".to_owned()),
679 PairredExtras {
680 package_id,
681 crate_extra: CrateAnnotations {
682 data_glob: Some(BTreeSet::from(["**/data_glob/**".to_owned()])),
683 ..CrateAnnotations::default()
684 },
685 },
686 );
687
688 let context = CrateContext::new(
689 crate_annotation,
690 &annotations.metadata.packages,
691 &annotations.lockfile.crates,
692 &pairred_extras,
693 false,
694 );
695
696 assert_eq!(context.name, "common");
697 assert_eq!(
698 context.targets,
699 vec![
700 Rule::Library(TargetAttributes {
701 crate_name: "common".to_owned(),
702 crate_root: Some("lib.rs".to_owned()),
703 srcs: Glob::new_rust_srcs(),
704 }),
705 Rule::Binary(TargetAttributes {
706 crate_name: "common-bin".to_owned(),
707 crate_root: Some("main.rs".to_owned()),
708 srcs: Glob::new_rust_srcs(),
709 }),
710 ]
711 );
712 assert_eq!(
713 context.common_attrs.data_glob,
714 BTreeSet::from(["**/data_glob/**".to_owned()])
715 );
716 }
717
718 fn build_script_annotations() -> Annotations {
719 Annotations::new(
720 crate::test::metadata::build_scripts(),
721 crate::test::lockfile::build_scripts(),
722 crate::config::Config::default(),
723 )
724 .unwrap()
725 }
726
727 fn crate_type_annotations() -> Annotations {
728 Annotations::new(
729 crate::test::metadata::crate_types(),
730 crate::test::lockfile::crate_types(),
731 crate::config::Config::default(),
732 )
733 .unwrap()
734 }
735
736 #[test]
737 fn context_with_build_script() {
738 let annotations = build_script_annotations();
739
740 let package_id = PackageId {
741 repr: "openssl-sys 0.9.72 (registry+https://github.com/rust-lang/crates.io-index)"
742 .to_owned(),
743 };
744
745 let crate_annotation = &annotations.metadata.crates[&package_id];
746
747 let context = CrateContext::new(
748 crate_annotation,
749 &annotations.metadata.packages,
750 &annotations.lockfile.crates,
751 &annotations.pairred_extras,
752 true,
753 );
754
755 assert_eq!(context.name, "openssl-sys");
756 assert!(context.build_script_attrs.is_some());
757 assert_eq!(
758 context.targets,
759 vec![
760 Rule::Library(TargetAttributes {
761 crate_name: "openssl_sys".to_owned(),
762 crate_root: Some("src/lib.rs".to_owned()),
763 srcs: Glob::new_rust_srcs(),
764 }),
765 Rule::BuildScript(TargetAttributes {
766 crate_name: "build_script_main".to_owned(),
767 crate_root: Some("build/main.rs".to_owned()),
768 srcs: Glob::new_rust_srcs(),
769 })
770 ]
771 );
772
773 // Cargo build scripts should include all sources
774 assert!(context.build_script_attrs.unwrap().data_glob.contains("**"));
775 }
776
777 #[test]
778 fn context_disabled_build_script() {
779 let annotations = build_script_annotations();
780
781 let package_id = PackageId {
782 repr: "openssl-sys 0.9.72 (registry+https://github.com/rust-lang/crates.io-index)"
783 .to_owned(),
784 };
785
786 let crate_annotation = &annotations.metadata.crates[&package_id];
787
788 let context = CrateContext::new(
789 crate_annotation,
790 &annotations.metadata.packages,
791 &annotations.lockfile.crates,
792 &annotations.pairred_extras,
793 false,
794 );
795
796 assert_eq!(context.name, "openssl-sys");
797 assert!(context.build_script_attrs.is_none());
798 assert_eq!(
799 context.targets,
800 vec![Rule::Library(TargetAttributes {
801 crate_name: "openssl_sys".to_owned(),
802 crate_root: Some("src/lib.rs".to_owned()),
803 srcs: Glob::new_rust_srcs(),
804 })],
805 );
806 }
807
808 #[test]
809 fn context_rlib_crate_type() {
810 let annotations = crate_type_annotations();
811
812 let package_id = PackageId {
813 repr: "sysinfo 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)"
814 .to_owned(),
815 };
816
817 let crate_annotation = &annotations.metadata.crates[&package_id];
818
819 let context = CrateContext::new(
820 crate_annotation,
821 &annotations.metadata.packages,
822 &annotations.lockfile.crates,
823 &annotations.pairred_extras,
824 false,
825 );
826
827 assert_eq!(context.name, "sysinfo");
828 assert!(context.build_script_attrs.is_none());
829 assert_eq!(
830 context.targets,
831 vec![Rule::Library(TargetAttributes {
832 crate_name: "sysinfo".to_owned(),
833 crate_root: Some("src/lib.rs".to_owned()),
834 srcs: Glob::new_rust_srcs(),
835 })],
836 );
837 }
838}