1use crate::Package;
2use anyhow::{bail, Result};
3
4pub(crate) fn parse_requirements_txt(contents: &str) -> Result<Vec<Package>> {
5 let mut packages = vec![];
6 for line in contents.lines() {
7 let line = line.trim();
8 let line = line.trim_end_matches('\\');
9 if line.is_empty() {
10 continue;
11 }
12 if line.trim_start().starts_with('#') {
13 continue;
14 }
15 if line.starts_with("--") {
16 continue;
17 }
18 let split: Vec<_> = line.split("==").collect();
19 if split.len() != 2 {
20 bail!("Expected <package>==<version> in '{line}'");
21 }
22 let name = &split[0].trim();
23 let version = &split[1].trim();
24 let package = Package::new(name, version);
25 packages.push(package);
26 }
27 Ok(packages)
28}
29
30#[cfg(test)]
31mod tests {
32
33 use super::*;
34
35 #[test]
36 fn test_parse_simple_requirements_txt() {
37 let contents = r#"
38# This file is autogenerated by pip-compile with Python 3.10
39# by the following command:
40#
41# pip-compile --output-file=requirements.txt pyproject.toml
42#
43asgiref==3.6.0
44 # via django
45django==4.1.7
46 # via my-cool-django-app (pyproject.toml)
47"#;
48
49 let packages = parse_requirements_txt(contents).unwrap();
50 assert_eq!(
51 &packages,
52 &[
53 Package::new("asgiref", "3.6.0"),
54 Package::new("django", "4.1.7")
55 ]
56 );
57 }
58
59 #[test]
60 fn test_parse_requirements_txt_with_hashes() {
61 let contents = r#"
62# This file is autogenerated by pip-compile with Python 3.10
63# by the following command:
64#
65# pip-compile --output-file=requirements.txt pyproject.toml
66#
67asgiref==3.6.0 \
68 --hash=sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac \
69 --hash=sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506
70
71 # via django
72django==4.1.7
73 --hash=sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506
74 --hash=sha256:f2f431e75adc40039ace496ad3b9f17227022e8b11566f4b363da44c7e44761e
75 # via -r requirements.in
76"#;
77
78 let packages = parse_requirements_txt(contents).unwrap();
79 assert_eq!(
80 &packages,
81 &[
82 Package::new("asgiref", "3.6.0"),
83 Package::new("django", "4.1.7")
84 ]
85 );
86 }
87}