1
1
use crate :: package:: Package ;
2
2
use anyhow:: Result ;
3
3
use console:: style;
4
+ use futures:: stream:: { self , StreamExt } ;
4
5
use serde:: { Deserialize , Serialize } ;
5
6
use std:: collections:: HashMap ;
6
7
@@ -17,7 +18,7 @@ pub struct ConfigFile {
17
18
/// A wrapper to [ConfigFile]. This _is_ necessary.
18
19
/// Any alternatives will end up being more ugly than this. (trust me i tried)
19
20
/// There is no way to automatically deserialize the map into a vec.
20
- struct ConfigWrapper {
21
+ struct ParsedConfig {
21
22
// support NPM package.json files (also allows gpm -c package.json -u)
22
23
#[ serde( alias = "dependencies" ) ]
23
24
packages : HashMap < String , String > ,
@@ -36,33 +37,40 @@ impl std::fmt::Display for ConfigType {
36
37
}
37
38
}
38
39
39
- impl From < ConfigWrapper > for ConfigFile {
40
- fn from ( from : ConfigWrapper ) -> Self {
40
+ impl From < ConfigFile > for ParsedConfig {
41
+ fn from ( from : ConfigFile ) -> Self {
41
42
Self {
42
43
packages : from
43
44
. packages
44
45
. into_iter ( )
45
- . map ( |( name , version ) | Package :: new ( name, version ) . unwrap ( ) )
46
+ . map ( |p| ( p . name , p . version ) )
46
47
. collect ( ) ,
47
48
}
48
49
}
49
50
}
50
51
51
- impl From < ConfigFile > for ConfigWrapper {
52
- fn from ( from : ConfigFile ) -> Self {
53
- Self {
54
- packages : from
55
- . packages
56
- . into_iter ( )
57
- . map ( |p| ( p. name , p. version ) )
58
- . collect ( ) ,
59
- }
52
+ impl ParsedConfig {
53
+ pub fn parse ( txt : & str , t : ConfigType ) -> Result < Self > {
54
+ Ok ( match t {
55
+ ConfigType :: TOML => toml:: from_str :: < ParsedConfig > ( txt) ?,
56
+ ConfigType :: JSON => deser_hjson:: from_str :: < ParsedConfig > ( txt) ?,
57
+ ConfigType :: YAML => serde_yaml:: from_str :: < ParsedConfig > ( txt) ?,
58
+ } )
59
+ }
60
+
61
+ pub async fn into_configfile ( self ) -> ConfigFile {
62
+ let packages = stream:: iter ( self . packages . into_iter ( ) )
63
+ . map ( |( name, version) | async { Package :: new ( name, version) . await . unwrap ( ) } )
64
+ . buffer_unordered ( crate :: PARALLEL )
65
+ . collect :: < Vec < Package > > ( )
66
+ . await ;
67
+ ConfigFile { packages }
60
68
}
61
69
}
62
70
63
71
impl ConfigFile {
64
72
pub fn print ( self , t : ConfigType ) -> String {
65
- let w = ConfigWrapper :: from ( self ) ;
73
+ let w = ParsedConfig :: from ( self ) ;
66
74
match t {
67
75
ConfigType :: JSON => serde_json:: to_string_pretty ( & w) . unwrap ( ) ,
68
76
ConfigType :: YAML => serde_yaml:: to_string ( & w) . unwrap ( ) ,
@@ -72,20 +80,24 @@ impl ConfigFile {
72
80
73
81
/// Creates a new [ConfigFile] from the given text
74
82
/// Panics if the file cant be parsed as toml, hjson or yaml.
75
- pub fn new ( contents : & String ) -> Self {
76
- if contents. len ( ) == 0 {
83
+ pub async fn new ( contents : & String ) -> Self {
84
+ if contents. is_empty ( ) {
77
85
panic ! ( "Empty CFG" ) ;
78
86
}
79
87
80
88
// definetly not going to backfire
81
89
let mut cfg = if contents. as_bytes ( ) [ 0 ] == b'{' {
82
90
// json gets brute forced first so this isnt really needed
83
- Self :: parse ( contents, ConfigType :: JSON ) . expect ( "Parsing CFG from JSON should work" )
91
+ Self :: parse ( contents, ConfigType :: JSON )
92
+ . await
93
+ . expect ( "Parsing CFG from JSON should work" )
84
94
} else if contents. len ( ) > 3 && contents[ ..3 ] == * "---" {
85
- Self :: parse ( contents, ConfigType :: YAML ) . expect ( "Parsing CFG from YAML should work" )
95
+ Self :: parse ( contents, ConfigType :: YAML )
96
+ . await
97
+ . expect ( "Parsing CFG from YAML should work" )
86
98
} else {
87
99
for i in [ ConfigType :: JSON , ConfigType :: YAML , ConfigType :: TOML ] . into_iter ( ) {
88
- let res = Self :: parse ( contents, i. clone ( ) ) ;
100
+ let res = Self :: parse ( contents, i) . await ;
89
101
90
102
// im sure theres some kind of idiomatic rust way to do this that i dont know of
91
103
if res. is_ok ( ) {
@@ -106,30 +118,19 @@ impl ConfigFile {
106
118
cfg
107
119
}
108
120
109
- pub fn parse ( txt : & String , t : ConfigType ) -> Result < Self > {
110
- type W = ConfigWrapper ;
111
- Ok ( match t {
112
- ConfigType :: TOML => toml:: from_str :: < W > ( txt) ?. into ( ) ,
113
- ConfigType :: JSON => deser_hjson:: from_str :: < W > ( txt) ?. into ( ) ,
114
- ConfigType :: YAML => serde_yaml:: from_str :: < W > ( txt) ?. into ( ) ,
115
- } )
121
+ pub async fn parse ( txt : & str , t : ConfigType ) -> Result < Self > {
122
+ Ok ( ParsedConfig :: parse ( txt, t) ?. into_configfile ( ) . await )
116
123
}
117
124
118
125
/// Creates a lockfile for this config file.
119
126
/// note: Lockfiles are currently unused.
120
- pub fn lock ( & mut self ) -> String {
121
- let mut pkgs = vec ! [ ] as Vec < Package > ;
122
- self . collect ( )
123
- . into_iter ( )
124
- . filter ( |p| p. is_installed ( ) )
125
- . for_each ( |mut p| {
126
- if p. integrity . is_empty ( ) {
127
- p. integrity = p
128
- . get_integrity ( )
129
- . expect ( "Should be able to get package integrity" ) ;
130
- }
131
- pkgs. push ( p) ;
132
- } ) ;
127
+ pub async fn lock ( & mut self ) -> String {
128
+ let mut pkgs = vec ! [ ] ;
129
+ for mut p in self . collect ( ) {
130
+ if p. is_installed ( ) && p. get_manifest ( ) . await . is_ok ( ) {
131
+ pkgs. push ( p)
132
+ } ;
133
+ }
133
134
serde_json:: to_string_pretty ( & pkgs) . unwrap ( )
134
135
}
135
136
@@ -164,13 +165,13 @@ impl ConfigFile {
164
165
mod tests {
165
166
use crate :: config_file:: * ;
166
167
167
- #[ test]
168
- fn parse ( ) {
168
+ #[ tokio :: test]
169
+ async fn parse ( ) {
169
170
let _t = crate :: test_utils:: mktemp ( ) ;
170
171
let cfgs: [ & mut ConfigFile ; 3 ] = [
171
- & mut ConfigFile :: new ( & r#"dependencies: { "@bendn/test": 2.0.10 }"# . into ( ) ) , // quoteless fails as a result of https://github.com/Canop/deser-hjson/issues/9
172
- & mut ConfigFile :: new ( & "dependencies:\n \" @bendn/test\" : 2.0.10" . into ( ) ) ,
173
- & mut ConfigFile :: new ( & "[dependencies]\n \" @bendn/test\" = \" 2.0.10\" " . into ( ) ) ,
172
+ & mut ConfigFile :: new ( & r#"dependencies: { "@bendn/test": 2.0.10 }"# . into ( ) ) . await , // quoteless fails as a result of https://github.com/Canop/deser-hjson/issues/9
173
+ & mut ConfigFile :: new ( & "dependencies:\n \" @bendn/test\" : 2.0.10" . into ( ) ) . await ,
174
+ & mut ConfigFile :: new ( & "[dependencies]\n \" @bendn/test\" = \" 2.0.10\" " . into ( ) ) . await ,
174
175
] ;
175
176
#[ derive( Debug , Deserialize , Clone , Eq , PartialEq ) ]
176
177
struct LockFileEntry {
@@ -189,9 +190,11 @@ mod tests {
189
190
cfg. packages[ 0 ] . dependencies[ 0 ] . to_string( ) ,
190
191
191
192
) ;
192
- cfg. for_each ( |p| p. download ( ) ) ;
193
+ for mut p in cfg. collect ( ) {
194
+ p. download ( ) . await
195
+ }
193
196
assert_eq ! (
194
- serde_json:: from_str:: <Vec <LockFileEntry >>( cfg. lock( ) . as_str( ) ) . unwrap( ) ,
197
+ serde_json:: from_str:: <Vec <LockFileEntry >>( cfg. lock( ) . await . as_str( ) ) . unwrap( ) ,
195
198
wanted_lockfile
196
199
) ;
197
200
}
0 commit comments