aboutsummaryrefslogtreecommitdiff
path: root/lib/src
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-12-29 05:23:38 +0000
committerAkshay <[email protected]>2022-01-08 10:33:10 +0000
commitd1ff222bcf94152cd657233cffd8c14a45788c26 (patch)
treefb8c94daefe0384a48b503fdd4bfaff905d78e2f /lib/src
parent94a2edf57340ac3f3a2276c88a221ba3125172af (diff)
allow for version based lints
Diffstat (limited to 'lib/src')
-rw-r--r--lib/src/lib.rs4
-rw-r--r--lib/src/lints.rs1
-rw-r--r--lib/src/lints/bool_comparison.rs4
-rw-r--r--lib/src/lints/collapsible_let_in.rs4
-rw-r--r--lib/src/lints/deprecated_is_null.rs4
-rw-r--r--lib/src/lints/empty_inherit.rs4
-rw-r--r--lib/src/lints/empty_let_in.rs4
-rw-r--r--lib/src/lints/empty_pattern.rs4
-rw-r--r--lib/src/lints/eta_reduction.rs4
-rw-r--r--lib/src/lints/faster_groupby.rs72
-rw-r--r--lib/src/lints/legacy_let_syntax.rs4
-rw-r--r--lib/src/lints/manual_inherit.rs4
-rw-r--r--lib/src/lints/manual_inherit_from.rs4
-rw-r--r--lib/src/lints/redundant_pattern_bind.rs4
-rw-r--r--lib/src/lints/unquoted_splice.rs4
-rw-r--r--lib/src/lints/unquoted_uri.rs4
-rw-r--r--lib/src/lints/useless_parens.rs4
-rw-r--r--lib/src/session.rs103
18 files changed, 207 insertions, 29 deletions
diff --git a/lib/src/lib.rs b/lib/src/lib.rs
index a25b814..cc4818a 100644
--- a/lib/src/lib.rs
+++ b/lib/src/lib.rs
@@ -1,9 +1,11 @@
1#![recursion_limit = "1024"] 1#![recursion_limit = "1024"]
2mod lints; 2mod lints;
3mod make; 3mod make;
4pub mod session;
4mod utils; 5mod utils;
5 6
6pub use lints::LINTS; 7pub use lints::LINTS;
8use session::SessionInfo;
7 9
8use rnix::{parser::ParseError, SyntaxElement, SyntaxKind, TextRange}; 10use rnix::{parser::ParseError, SyntaxElement, SyntaxKind, TextRange};
9use std::{convert::Into, default::Default}; 11use std::{convert::Into, default::Default};
@@ -221,7 +223,7 @@ impl Serialize for Suggestion {
221/// Lint logic is defined via this trait. Do not implement manually, 223/// Lint logic is defined via this trait. Do not implement manually,
222/// look at the `lint` attribute macro instead for implementing rules 224/// look at the `lint` attribute macro instead for implementing rules
223pub trait Rule { 225pub trait Rule {
224 fn validate(&self, node: &SyntaxElement) -> Option<Report>; 226 fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option<Report>;
225} 227}
226 228
227/// Contains information about the lint itself. Do not implement manually, 229/// Contains information about the lint itself. Do not implement manually,
diff --git a/lib/src/lints.rs b/lib/src/lints.rs
index 5de6b65..0add458 100644
--- a/lib/src/lints.rs
+++ b/lib/src/lints.rs
@@ -15,4 +15,5 @@ lints! {
15 unquoted_uri, 15 unquoted_uri,
16 deprecated_is_null, 16 deprecated_is_null,
17 empty_inherit, 17 empty_inherit,
18 faster_groupby,
18} 19}
diff --git a/lib/src/lints/bool_comparison.rs b/lib/src/lints/bool_comparison.rs
index ed1e8bb..ef7f5d2 100644
--- a/lib/src/lints/bool_comparison.rs
+++ b/lib/src/lints/bool_comparison.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -35,7 +35,7 @@ use rnix::{
35struct BoolComparison; 35struct BoolComparison;
36 36
37impl Rule for BoolComparison { 37impl Rule for BoolComparison {
38 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 38 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
39 if_chain! { 39 if_chain! {
40 if let NodeOrToken::Node(node) = node; 40 if let NodeOrToken::Node(node) = node;
41 if let Some(bin_expr) = BinOp::cast(node.clone()); 41 if let Some(bin_expr) = BinOp::cast(node.clone());
diff --git a/lib/src/lints/collapsible_let_in.rs b/lib/src/lints/collapsible_let_in.rs
index aa7e5a7..1c04d9c 100644
--- a/lib/src/lints/collapsible_let_in.rs
+++ b/lib/src/lints/collapsible_let_in.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -45,7 +45,7 @@ use rowan::Direction;
45struct CollapsibleLetIn; 45struct CollapsibleLetIn;
46 46
47impl Rule for CollapsibleLetIn { 47impl Rule for CollapsibleLetIn {
48 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 48 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
49 if_chain! { 49 if_chain! {
50 if let NodeOrToken::Node(node) = node; 50 if let NodeOrToken::Node(node) = node;
51 if let Some(let_in_expr) = LetIn::cast(node.clone()); 51 if let Some(let_in_expr) = LetIn::cast(node.clone());
diff --git a/lib/src/lints/deprecated_is_null.rs b/lib/src/lints/deprecated_is_null.rs
index c814e87..9e7c293 100644
--- a/lib/src/lints/deprecated_is_null.rs
+++ b/lib/src/lints/deprecated_is_null.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -35,7 +35,7 @@ use rnix::{
35struct DeprecatedIsNull; 35struct DeprecatedIsNull;
36 36
37impl Rule for DeprecatedIsNull { 37impl Rule for DeprecatedIsNull {
38 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 38 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
39 if_chain! { 39 if_chain! {
40 if let NodeOrToken::Node(node) = node; 40 if let NodeOrToken::Node(node) = node;
41 if let Some(apply) = Apply::cast(node.clone()); 41 if let Some(apply) = Apply::cast(node.clone());
diff --git a/lib/src/lints/empty_inherit.rs b/lib/src/lints/empty_inherit.rs
index 9ae4cf2..871c218 100644
--- a/lib/src/lints/empty_inherit.rs
+++ b/lib/src/lints/empty_inherit.rs
@@ -1,4 +1,4 @@
1use crate::{make, utils, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, utils, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -29,7 +29,7 @@ use rnix::{
29struct EmptyInherit; 29struct EmptyInherit;
30 30
31impl Rule for EmptyInherit { 31impl Rule for EmptyInherit {
32 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 32 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
33 if_chain! { 33 if_chain! {
34 if let NodeOrToken::Node(node) = node; 34 if let NodeOrToken::Node(node) = node;
35 if let Some(inherit_stmt) = Inherit::cast(node.clone()); 35 if let Some(inherit_stmt) = Inherit::cast(node.clone());
diff --git a/lib/src/lints/empty_let_in.rs b/lib/src/lints/empty_let_in.rs
index d33d0ae..e42f658 100644
--- a/lib/src/lints/empty_let_in.rs
+++ b/lib/src/lints/empty_let_in.rs
@@ -1,4 +1,4 @@
1use crate::{Metadata, Report, Rule, Suggestion}; 1use crate::{session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -34,7 +34,7 @@ use rnix::{
34struct EmptyLetIn; 34struct EmptyLetIn;
35 35
36impl Rule for EmptyLetIn { 36impl Rule for EmptyLetIn {
37 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 37 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
38 if_chain! { 38 if_chain! {
39 if let NodeOrToken::Node(node) = node; 39 if let NodeOrToken::Node(node) = node;
40 if let Some(let_in_expr) = LetIn::cast(node.clone()); 40 if let Some(let_in_expr) = LetIn::cast(node.clone());
diff --git a/lib/src/lints/empty_pattern.rs b/lib/src/lints/empty_pattern.rs
index f66a3b1..e03708b 100644
--- a/lib/src/lints/empty_pattern.rs
+++ b/lib/src/lints/empty_pattern.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -43,7 +43,7 @@ use rnix::{
43struct EmptyPattern; 43struct EmptyPattern;
44 44
45impl Rule for EmptyPattern { 45impl Rule for EmptyPattern {
46 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 46 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
47 if_chain! { 47 if_chain! {
48 if let NodeOrToken::Node(node) = node; 48 if let NodeOrToken::Node(node) = node;
49 if let Some(pattern) = Pattern::cast(node.clone()); 49 if let Some(pattern) = Pattern::cast(node.clone());
diff --git a/lib/src/lints/eta_reduction.rs b/lib/src/lints/eta_reduction.rs
index 580f4a0..8e9d2a3 100644
--- a/lib/src/lints/eta_reduction.rs
+++ b/lib/src/lints/eta_reduction.rs
@@ -1,4 +1,4 @@
1use crate::{Metadata, Report, Rule, Suggestion}; 1use crate::{session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -42,7 +42,7 @@ use rnix::{
42struct EtaReduction; 42struct EtaReduction;
43 43
44impl Rule for EtaReduction { 44impl Rule for EtaReduction {
45 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 45 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
46 if_chain! { 46 if_chain! {
47 if let NodeOrToken::Node(node) = node; 47 if let NodeOrToken::Node(node) = node;
48 if let Some(lambda_expr) = Lambda::cast(node.clone()); 48 if let Some(lambda_expr) = Lambda::cast(node.clone());
diff --git a/lib/src/lints/faster_groupby.rs b/lib/src/lints/faster_groupby.rs
new file mode 100644
index 0000000..c496125
--- /dev/null
+++ b/lib/src/lints/faster_groupby.rs
@@ -0,0 +1,72 @@
1use crate::{
2 make,
3 session::{SessionInfo, Version},
4 Metadata, Report, Rule, Suggestion,
5};
6
7use if_chain::if_chain;
8use macros::lint;
9use rnix::{
10 types::{Select, TypedNode},
11 NodeOrToken, SyntaxElement, SyntaxKind,
12};
13
14/// ## What it does
15/// Checks for `lib.groupBy`.
16///
17/// ## Why is this bad?
18/// Nix 2.5 introduces `builtins.groupBy` which is faster and does
19/// not require a lib import.
20///
21/// ## Example
22///
23/// ```nix
24/// lib.groupBy (x: if x > 2 then "big" else "small") [ 1 2 3 4 5 6 ];
25/// # { big = [ 3 4 5 6 ]; small = [ 1 2 ]; }
26/// ```
27///
28/// Replace `lib.groupBy` with `builtins.groupBy`:
29///
30/// ```
31/// builtins.groupBy (x: if x > 2 then "big" else "small") [ 1 2 3 4 5 6 ];
32/// ```
33#[lint(
34 name = "faster_groupby",
35 note = "Found lib.groupBy",
36 code = 15,
37 match_with = SyntaxKind::NODE_SELECT
38)]
39struct FasterGroupBy;
40
41impl Rule for FasterGroupBy {
42 fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option<Report> {
43 let lint_version = "nix (Nix) 2.5".parse::<Version>().unwrap();
44 if_chain! {
45 if sess.version() >= &lint_version;
46 if let NodeOrToken::Node(node) = node;
47 if let Some(select_expr) = Select::cast(node.clone());
48 if let Some(select_from) = select_expr.set();
49 if let Some(group_by_attr) = select_expr.index();
50
51 // a heuristic to lint on nixpkgs.lib.groupBy
52 // and lib.groupBy and its variants
53 if select_from.text().to_string() != "builtins";
54 if group_by_attr.text().to_string() == "groupBy";
55
56 then {
57 let at = node.text_range();
58 let replacement = {
59 let builtins = make::ident("builtins");
60 make::select(builtins.node(), &group_by_attr).node().clone()
61 };
62 let message = format!("Prefer `builtins.groupBy` over `{}.groupBy`", select_from);
63 Some(
64 self.report()
65 .suggest(at, message, Suggestion::new(at, replacement)),
66 )
67 } else {
68 None
69 }
70 }
71 }
72}
diff --git a/lib/src/lints/legacy_let_syntax.rs b/lib/src/lints/legacy_let_syntax.rs
index 5d0028b..e0b8980 100644
--- a/lib/src/lints/legacy_let_syntax.rs
+++ b/lib/src/lints/legacy_let_syntax.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -44,7 +44,7 @@ use rnix::{
44struct ManualInherit; 44struct ManualInherit;
45 45
46impl Rule for ManualInherit { 46impl Rule for ManualInherit {
47 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 47 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
48 if_chain! { 48 if_chain! {
49 if let NodeOrToken::Node(node) = node; 49 if let NodeOrToken::Node(node) = node;
50 if let Some(legacy_let) = LegacyLet::cast(node.clone()); 50 if let Some(legacy_let) = LegacyLet::cast(node.clone());
diff --git a/lib/src/lints/manual_inherit.rs b/lib/src/lints/manual_inherit.rs
index 7717dc9..4fddce5 100644
--- a/lib/src/lints/manual_inherit.rs
+++ b/lib/src/lints/manual_inherit.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -40,7 +40,7 @@ use rnix::{
40struct ManualInherit; 40struct ManualInherit;
41 41
42impl Rule for ManualInherit { 42impl Rule for ManualInherit {
43 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 43 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
44 if_chain! { 44 if_chain! {
45 if let NodeOrToken::Node(node) = node; 45 if let NodeOrToken::Node(node) = node;
46 if let Some(key_value_stmt) = KeyValue::cast(node.clone()); 46 if let Some(key_value_stmt) = KeyValue::cast(node.clone());
diff --git a/lib/src/lints/manual_inherit_from.rs b/lib/src/lints/manual_inherit_from.rs
index 05d6bc8..a62a6c7 100644
--- a/lib/src/lints/manual_inherit_from.rs
+++ b/lib/src/lints/manual_inherit_from.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -40,7 +40,7 @@ use rnix::{
40struct ManualInherit; 40struct ManualInherit;
41 41
42impl Rule for ManualInherit { 42impl Rule for ManualInherit {
43 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 43 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
44 if_chain! { 44 if_chain! {
45 if let NodeOrToken::Node(node) = node; 45 if let NodeOrToken::Node(node) = node;
46 if let Some(key_value_stmt) = KeyValue::cast(node.clone()); 46 if let Some(key_value_stmt) = KeyValue::cast(node.clone());
diff --git a/lib/src/lints/redundant_pattern_bind.rs b/lib/src/lints/redundant_pattern_bind.rs
index 88ce4b0..56957ce 100644
--- a/lib/src/lints/redundant_pattern_bind.rs
+++ b/lib/src/lints/redundant_pattern_bind.rs
@@ -1,4 +1,4 @@
1use crate::{Metadata, Report, Rule, Suggestion}; 1use crate::{session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -35,7 +35,7 @@ use rnix::{
35struct RedundantPatternBind; 35struct RedundantPatternBind;
36 36
37impl Rule for RedundantPatternBind { 37impl Rule for RedundantPatternBind {
38 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 38 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
39 if_chain! { 39 if_chain! {
40 if let NodeOrToken::Node(node) = node; 40 if let NodeOrToken::Node(node) = node;
41 if let Some(pattern) = Pattern::cast(node.clone()); 41 if let Some(pattern) = Pattern::cast(node.clone());
diff --git a/lib/src/lints/unquoted_splice.rs b/lib/src/lints/unquoted_splice.rs
index 7649fbc..ba1641a 100644
--- a/lib/src/lints/unquoted_splice.rs
+++ b/lib/src/lints/unquoted_splice.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -40,7 +40,7 @@ use rnix::{
40struct UnquotedSplice; 40struct UnquotedSplice;
41 41
42impl Rule for UnquotedSplice { 42impl Rule for UnquotedSplice {
43 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 43 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
44 if_chain! { 44 if_chain! {
45 if let NodeOrToken::Node(node) = node; 45 if let NodeOrToken::Node(node) = node;
46 if Dynamic::cast(node.clone()).is_some(); 46 if Dynamic::cast(node.clone()).is_some();
diff --git a/lib/src/lints/unquoted_uri.rs b/lib/src/lints/unquoted_uri.rs
index 8835338..440b278 100644
--- a/lib/src/lints/unquoted_uri.rs
+++ b/lib/src/lints/unquoted_uri.rs
@@ -1,4 +1,4 @@
1use crate::{make, Metadata, Report, Rule, Suggestion}; 1use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -46,7 +46,7 @@ use rnix::{types::TypedNode, NodeOrToken, SyntaxElement, SyntaxKind};
46struct UnquotedUri; 46struct UnquotedUri;
47 47
48impl Rule for UnquotedUri { 48impl Rule for UnquotedUri {
49 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 49 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
50 if_chain! { 50 if_chain! {
51 if let NodeOrToken::Token(token) = node; 51 if let NodeOrToken::Token(token) = node;
52 then { 52 then {
diff --git a/lib/src/lints/useless_parens.rs b/lib/src/lints/useless_parens.rs
index 09d6f04..9cba4b3 100644
--- a/lib/src/lints/useless_parens.rs
+++ b/lib/src/lints/useless_parens.rs
@@ -1,4 +1,4 @@
1use crate::{Diagnostic, Metadata, Report, Rule, Suggestion}; 1use crate::{session::SessionInfo, Diagnostic, Metadata, Report, Rule, Suggestion};
2 2
3use if_chain::if_chain; 3use if_chain::if_chain;
4use macros::lint; 4use macros::lint;
@@ -45,7 +45,7 @@ use rnix::{
45struct UselessParens; 45struct UselessParens;
46 46
47impl Rule for UselessParens { 47impl Rule for UselessParens {
48 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 48 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> {
49 if_chain! { 49 if_chain! {
50 if let NodeOrToken::Node(node) = node; 50 if let NodeOrToken::Node(node) = node;
51 if let Some(parsed_type_node) = ParsedType::cast(node.clone()); 51 if let Some(parsed_type_node) = ParsedType::cast(node.clone());
diff --git a/lib/src/session.rs b/lib/src/session.rs
new file mode 100644
index 0000000..8d142ec
--- /dev/null
+++ b/lib/src/session.rs
@@ -0,0 +1,103 @@
1use std::{cmp::Ordering, str::FromStr};
2
3#[derive(Copy, Clone, Debug, Eq, PartialEq)]
4pub struct Version {
5 major: u16,
6 minor: u16,
7 patch: Option<u16>,
8}
9
10impl Ord for Version {
11 fn cmp(&self, other: &Self) -> Ordering {
12 let score = |v: &Version| v.major * 100 + v.minor * 10 + v.patch.unwrap_or(0);
13 score(self).cmp(&score(other))
14 }
15}
16
17impl PartialOrd for Version {
18 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
19 Some(self.cmp(other))
20 }
21}
22
23fn parse_number(s: &str) -> Option<u16> {
24 s.chars()
25 .take_while(|c| c.is_digit(10))
26 .collect::<String>()
27 .parse::<u16>()
28 .ok()
29}
30
31fn parse_version(s: &str) -> Option<Version> {
32 match s.split(' ').collect::<Vec<_>>().as_slice() {
33 [_, _, version] => {
34 let mut parts = version.split('.');
35 let major = parse_number(parts.next()?)?;
36 let minor = parse_number(parts.next()?)?;
37 let patch = parts.next().map(|p| parse_number(p)).flatten();
38 Some(Version {
39 major,
40 minor,
41 patch,
42 })
43 }
44 _ => None,
45 }
46}
47
48impl FromStr for Version {
49 type Err = ();
50 fn from_str(s: &str) -> Result<Self, Self::Err> {
51 parse_version(s).ok_or(())
52 }
53}
54
55#[non_exhaustive]
56pub struct SessionInfo {
57 nix_version: Version,
58}
59
60impl SessionInfo {
61 pub fn from_version(nix_version: Version) -> Self {
62 Self { nix_version }
63 }
64
65 pub fn version(&self) -> &Version {
66 &self.nix_version
67 }
68}
69
70pub fn get_nix_version() -> Option<Version> {
71 "nix (Nix) 2.4pre20211006_53e4794".parse::<Version>().ok()
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn parse_trivial() {
80 let v = "nix (Nix) 1.6.1".parse::<Version>().ok();
81 assert!(v.is_some())
82 }
83
84 #[test]
85 fn parse() {
86 let v = "nix (Nix) 2.4pre20211006_53e4794".parse::<Version>().ok();
87 assert!(v.is_some())
88 }
89
90 #[test]
91 fn compare_trivial() {
92 let v1 = "nix (Nix) 1.6.1".parse::<Version>().ok();
93 let v2 = "nix (Nix) 1.7.2".parse::<Version>().ok();
94 assert!(v2 > v1);
95 }
96
97 #[test]
98 fn compare() {
99 let v1 = "nix (Nix) 1.7".parse::<Version>().ok();
100 let v2 = "nix (Nix) 2.4pre20211006_53e4794".parse::<Version>().ok();
101 assert!(v2 >= v1);
102 }
103}