@@ -24,78 +24,94 @@ pub enum TarballError {
24
24
Io ( #[ from] std:: io:: Error ) ,
25
25
}
26
26
27
- pub fn get_package_store_folder_name ( input : & str , version : & str ) -> String {
28
- format ! ( "{0}@{1}" , input. replace( '/' , "+" ) , version)
29
- }
27
+ #[ derive( Debug ) ]
28
+ pub struct TarballManager ;
30
29
31
- #[ instrument]
32
- pub async fn download_tarball ( url : & str , tarball_path : & Path ) -> Result < ( ) , TarballError > {
33
- let mut stream = reqwest:: get ( url) . await ?. bytes_stream ( ) ;
34
- let mut file = File :: create ( tarball_path) ?;
35
- event ! ( Level :: DEBUG , "downloading tarball to {}" , tarball_path. display( ) ) ;
36
-
37
- while let Some ( item) = stream. next ( ) . await {
38
- let chunk = item. map_err ( TarballError :: Network ) ?;
39
- file. write_all ( & chunk) ?;
30
+ impl Default for TarballManager {
31
+ fn default ( ) -> Self {
32
+ Self :: new ( )
40
33
}
41
-
42
- Ok ( ( ) )
43
34
}
44
35
45
- #[ instrument]
46
- pub fn extract_tarball ( tarball_path : & Path , extract_path : & Path ) -> Result < ( ) , TarballError > {
47
- let unpack_path = env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
48
- event ! ( Level :: DEBUG , "unpacking tarball to {}" , unpack_path. display( ) ) ;
49
- let tar_gz = File :: open ( tarball_path) ?;
50
- let tar = GzDecoder :: new ( tar_gz) ;
51
- let mut archive = Archive :: new ( tar) ;
52
- archive. unpack ( & unpack_path) ?;
53
- fs:: remove_file ( tarball_path) ?;
54
- fs:: create_dir_all ( extract_path) ?;
55
- // Check if extract_path is empty or not.
56
- // This is due by a race condition causing 2 different threads to download and
57
- // extract to the same folder. Likely be fixed with mutex locks.
58
- // TODO: Remove this when we have some sort of thread safety
59
- if extract_path. read_dir ( ) ?. next ( ) . is_none ( ) {
60
- fs:: rename ( unpack_path. join ( "package" ) , extract_path) ?;
36
+ impl TarballManager {
37
+ pub fn new ( ) -> Self {
38
+ TarballManager { }
61
39
}
62
- fs:: remove_dir_all ( & unpack_path) ?;
63
- Ok ( ( ) )
64
- }
65
40
66
- #[ instrument]
67
- pub async fn download_dependency (
68
- name : & str ,
69
- url : & str ,
70
- save_path : & Path ,
71
- symlink_to : & Path ,
72
- ) -> Result < ( ) , TarballError > {
73
- // If name contains `/` such as @fastify/error, we need to make sure that @fastify folder
74
- // exists before we symlink to that directory.
75
- if name. contains ( '/' ) {
76
- fs:: create_dir_all ( symlink_to. parent ( ) . unwrap ( ) ) ?;
41
+ #[ instrument]
42
+ async fn download ( & self , url : & str , tarball_path : & Path ) -> Result < ( ) , TarballError > {
43
+ let mut stream = reqwest:: get ( url) . await ?. bytes_stream ( ) ;
44
+ let mut file = File :: create ( tarball_path) ?;
45
+ event ! ( Level :: DEBUG , "downloading tarball to {}" , tarball_path. display( ) ) ;
46
+
47
+ while let Some ( item) = stream. next ( ) . await {
48
+ let chunk = item. map_err ( TarballError :: Network ) ?;
49
+ file. write_all ( & chunk) ?;
50
+ }
51
+
52
+ Ok ( ( ) )
77
53
}
78
54
79
- // Do not try to install dependency if this version already exists in package.json
80
- if save_path. exists ( ) {
81
- if !symlink_to. is_symlink ( ) {
82
- symlink_dir ( & save_path. to_path_buf ( ) , & symlink_to. to_path_buf ( ) ) ?;
55
+ #[ instrument]
56
+ fn extract ( & self , tarball_path : & Path , extract_path : & Path ) -> Result < ( ) , TarballError > {
57
+ let unpack_path = env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
58
+ event ! ( Level :: DEBUG , "unpacking tarball to {}" , unpack_path. display( ) ) ;
59
+ let tar_gz = File :: open ( tarball_path) ?;
60
+ let tar = GzDecoder :: new ( tar_gz) ;
61
+ let mut archive = Archive :: new ( tar) ;
62
+ archive. unpack ( & unpack_path) ?;
63
+ fs:: remove_file ( tarball_path) ?;
64
+ fs:: create_dir_all ( extract_path) ?;
65
+ // Check if extract_path is empty or not.
66
+ // This is due by a race condition causing 2 different threads to download and
67
+ // extract to the same folder. Likely be fixed with mutex locks.
68
+ // TODO: Remove this when we have some sort of thread safety
69
+ if extract_path. read_dir ( ) ?. next ( ) . is_none ( ) {
70
+ fs:: rename ( unpack_path. join ( "package" ) , extract_path) ?;
83
71
}
84
- return Ok ( ( ) ) ;
72
+ fs:: remove_dir_all ( & unpack_path) ?;
73
+ Ok ( ( ) )
85
74
}
86
75
87
- let tarball_path = env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
88
- download_tarball ( url, & tarball_path) . await ?;
76
+ #[ instrument]
77
+ pub async fn download_dependency (
78
+ & self ,
79
+ name : & str ,
80
+ url : & str ,
81
+ save_path : & Path ,
82
+ symlink_to : & Path ,
83
+ ) -> Result < ( ) , TarballError > {
84
+ // If name contains `/` such as @fastify/error, we need to make sure that @fastify folder
85
+ // exists before we symlink to that directory.
86
+ if name. contains ( '/' ) {
87
+ fs:: create_dir_all ( symlink_to. parent ( ) . unwrap ( ) ) ?;
88
+ }
89
+
90
+ // Do not try to install dependency if this version already exists in package.json
91
+ if save_path. exists ( ) {
92
+ if !symlink_to. is_symlink ( ) {
93
+ symlink_dir ( & save_path. to_path_buf ( ) , & symlink_to. to_path_buf ( ) ) ?;
94
+ }
95
+ return Ok ( ( ) ) ;
96
+ }
89
97
90
- extract_tarball ( & tarball_path, save_path) ?;
98
+ let tarball_path = env:: temp_dir ( ) . join ( Uuid :: new_v4 ( ) . to_string ( ) ) ;
99
+ self . download ( url, & tarball_path) . await ?;
91
100
92
- // TODO: Currently symlink paths are absolute paths.
93
- // If you move the root folder to a different path, all symlinks will be broken.
94
- if !symlink_to. is_symlink ( ) {
95
- symlink_dir ( & save_path. to_path_buf ( ) , & symlink_to. to_path_buf ( ) ) ?;
101
+ self . extract ( & tarball_path, save_path) ?;
102
+
103
+ // TODO: Currently symlink paths are absolute paths.
104
+ // If you move the root folder to a different path, all symlinks will be broken.
105
+ if !symlink_to. is_symlink ( ) {
106
+ symlink_dir ( & save_path. to_path_buf ( ) , & symlink_to. to_path_buf ( ) ) ?;
107
+ }
108
+
109
+ Ok ( ( ) )
96
110
}
111
+ }
97
112
98
- Ok ( ( ) )
113
+ pub fn get_package_store_folder_name ( input : & str , version : & str ) -> String {
114
+ format ! ( "{0}@{1}" , input. replace( '/' , "+" ) , version)
99
115
}
100
116
101
117
#[ cfg( test) ]
@@ -132,14 +148,17 @@ mod tests {
132
148
let save_path = store_path. join ( "@fastify+error@3.3.0" ) ;
133
149
let symlink_path = node_modules_path. join ( "@fastify/error" ) ;
134
150
135
- download_dependency (
136
- "@fastify/error" ,
137
- "https://registry.npmjs.org/@fastify/error/-/error-3.3.0.tgz" ,
138
- & save_path. to_path_buf ( ) ,
139
- & symlink_path. to_path_buf ( ) ,
140
- )
141
- . await
142
- . unwrap ( ) ;
151
+ let manager = TarballManager :: new ( ) ;
152
+
153
+ manager
154
+ . download_dependency (
155
+ "@fastify/error" ,
156
+ "https://registry.npmjs.org/@fastify/error/-/error-3.3.0.tgz" ,
157
+ & save_path. to_path_buf ( ) ,
158
+ & symlink_path. to_path_buf ( ) ,
159
+ )
160
+ . await
161
+ . unwrap ( ) ;
143
162
144
163
// Validate if we delete the tar.gz file
145
164
assert ! ( !store_path. join( "@fastify+error@3.3.0.tar.gz" ) . exists( ) ) ;
0 commit comments