@@ -10,6 +10,10 @@ use walkdir::{DirEntry, WalkDir};
10
10
11
11
use crate :: { Crate , LINTCHECK_DOWNLOADS , LINTCHECK_SOURCES } ;
12
12
13
+ const DEFAULT_DOCS_LINK : & str = "https://docs.rs/{krate}/{version}/src/{krate}/{file}.html#{line}" ;
14
+ const DEFAULT_GITHUB_LINK : & str = "{url}/blob/{hash}/src/{file}#L{line}" ;
15
+ const DEFAULT_PATH_LINK : & str = "{path}/src/{file}:{line}" ;
16
+
13
17
/// List of sources to check, loaded from a .toml file
14
18
#[ derive( Debug , Deserialize ) ]
15
19
pub struct SourceList {
@@ -33,32 +37,60 @@ struct TomlCrate {
33
37
git_hash : Option < String > ,
34
38
path : Option < String > ,
35
39
options : Option < Vec < String > > ,
40
+ /// Magic values:
41
+ /// * `{krate}` will be replaced by `self.name`
42
+ /// * `{version}` will be replaced by `self.version`
43
+ /// * `{url}` will be replaced with `self.git_url`
44
+ /// * `{hash}` will be replaced with `self.git_hash`
45
+ /// * `{path}` will be replaced with `self.path`
46
+ /// * `{file}` will be replaced by the path after `src/`
47
+ /// * `{line}` will be replaced by the line
48
+ ///
49
+ /// If unset, this will be filled by [`read_crates`] since it depends on
50
+ /// the source.
51
+ online_link : Option < String > ,
52
+ }
53
+
54
+ impl TomlCrate {
55
+ fn file_link ( & self , default : & str ) -> String {
56
+ let mut link = self . online_link . clone ( ) . unwrap_or_else ( || default. to_string ( ) ) ;
57
+ link = link. replace ( "{krate}" , & self . name ) ;
58
+
59
+ if let Some ( version) = & self . version {
60
+ link = link. replace ( "{version}" , version) ;
61
+ }
62
+ if let Some ( url) = & self . git_url {
63
+ link = link. replace ( "{url}" , url) ;
64
+ }
65
+ if let Some ( hash) = & self . git_hash {
66
+ link = link. replace ( "{hash}" , hash) ;
67
+ }
68
+ if let Some ( path) = & self . path {
69
+ link = link. replace ( "{path}" , path) ;
70
+ }
71
+ link
72
+ }
36
73
}
37
74
38
75
/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
39
76
/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
77
+ #[ derive( Debug , Deserialize , Eq , Hash , PartialEq , Ord , PartialOrd ) ]
78
+ pub struct CrateWithSource {
79
+ pub name : String ,
80
+ pub source : CrateSource ,
81
+ pub file_link : String ,
82
+ pub options : Option < Vec < String > > ,
83
+ }
84
+
40
85
#[ derive( Debug , Deserialize , Eq , Hash , PartialEq , Ord , PartialOrd ) ]
41
86
pub enum CrateSource {
42
- CratesIo {
43
- name : String ,
44
- version : String ,
45
- options : Option < Vec < String > > ,
46
- } ,
47
- Git {
48
- name : String ,
49
- url : String ,
50
- commit : String ,
51
- options : Option < Vec < String > > ,
52
- } ,
53
- Path {
54
- name : String ,
55
- path : PathBuf ,
56
- options : Option < Vec < String > > ,
57
- } ,
87
+ CratesIo { version : String } ,
88
+ Git { url : String , commit : String } ,
89
+ Path { path : PathBuf } ,
58
90
}
59
91
60
92
/// Read a `lintcheck_crates.toml` file
61
- pub fn read_crates ( toml_path : & Path ) -> ( Vec < CrateSource > , RecursiveOptions ) {
93
+ pub fn read_crates ( toml_path : & Path ) -> ( Vec < CrateWithSource > , RecursiveOptions ) {
62
94
let toml_content: String =
63
95
fs:: read_to_string ( toml_path) . unwrap_or_else ( |_| panic ! ( "Failed to read {}" , toml_path. display( ) ) ) ;
64
96
let crate_list: SourceList =
@@ -71,23 +103,32 @@ pub fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
71
103
let mut crate_sources = Vec :: new ( ) ;
72
104
for tk in tomlcrates {
73
105
if let Some ( ref path) = tk. path {
74
- crate_sources. push ( CrateSource :: Path {
106
+ crate_sources. push ( CrateWithSource {
75
107
name : tk. name . clone ( ) ,
76
- path : PathBuf :: from ( path) ,
108
+ source : CrateSource :: Path {
109
+ path : PathBuf :: from ( path) ,
110
+ } ,
111
+ file_link : tk. file_link ( DEFAULT_PATH_LINK ) ,
77
112
options : tk. options . clone ( ) ,
78
113
} ) ;
79
114
} else if let Some ( ref version) = tk. version {
80
- crate_sources. push ( CrateSource :: CratesIo {
115
+ crate_sources. push ( CrateWithSource {
81
116
name : tk. name . clone ( ) ,
82
- version : version. to_string ( ) ,
117
+ source : CrateSource :: CratesIo {
118
+ version : version. to_string ( ) ,
119
+ } ,
120
+ file_link : tk. file_link ( DEFAULT_DOCS_LINK ) ,
83
121
options : tk. options . clone ( ) ,
84
122
} ) ;
85
123
} else if tk. git_url . is_some ( ) && tk. git_hash . is_some ( ) {
86
124
// otherwise, we should have a git source
87
- crate_sources. push ( CrateSource :: Git {
125
+ crate_sources. push ( CrateWithSource {
88
126
name : tk. name . clone ( ) ,
89
- url : tk. git_url . clone ( ) . unwrap ( ) ,
90
- commit : tk. git_hash . clone ( ) . unwrap ( ) ,
127
+ source : CrateSource :: Git {
128
+ url : tk. git_url . clone ( ) . unwrap ( ) ,
129
+ commit : tk. git_hash . clone ( ) . unwrap ( ) ,
130
+ } ,
131
+ file_link : tk. file_link ( DEFAULT_GITHUB_LINK ) ,
91
132
options : tk. options . clone ( ) ,
92
133
} ) ;
93
134
} else {
@@ -117,7 +158,7 @@ pub fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
117
158
( crate_sources, crate_list. recursive )
118
159
}
119
160
120
- impl CrateSource {
161
+ impl CrateWithSource {
121
162
/// Makes the sources available on the disk for clippy to check.
122
163
/// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
123
164
/// copies a local folder
@@ -139,8 +180,11 @@ impl CrateSource {
139
180
retries += 1 ;
140
181
}
141
182
}
142
- match self {
143
- CrateSource :: CratesIo { name, version, options } => {
183
+ let name = & self . name ;
184
+ let options = & self . options ;
185
+ let file_link = & self . file_link ;
186
+ match & self . source {
187
+ CrateSource :: CratesIo { version } => {
144
188
let extract_dir = PathBuf :: from ( LINTCHECK_SOURCES ) ;
145
189
let krate_download_dir = PathBuf :: from ( LINTCHECK_DOWNLOADS ) ;
146
190
@@ -171,14 +215,10 @@ impl CrateSource {
171
215
name : name. clone ( ) ,
172
216
path : extract_dir. join ( format ! ( "{name}-{version}/" ) ) ,
173
217
options : options. clone ( ) ,
218
+ base_url : file_link. clone ( ) ,
174
219
}
175
220
} ,
176
- CrateSource :: Git {
177
- name,
178
- url,
179
- commit,
180
- options,
181
- } => {
221
+ CrateSource :: Git { url, commit } => {
182
222
let repo_path = {
183
223
let mut repo_path = PathBuf :: from ( LINTCHECK_SOURCES ) ;
184
224
// add a -git suffix in case we have the same crate from crates.io and a git repo
@@ -217,9 +257,10 @@ impl CrateSource {
217
257
name : name. clone ( ) ,
218
258
path : repo_path,
219
259
options : options. clone ( ) ,
260
+ base_url : file_link. clone ( ) ,
220
261
}
221
262
} ,
222
- CrateSource :: Path { name , path, options } => {
263
+ CrateSource :: Path { path } => {
223
264
fn is_cache_dir ( entry : & DirEntry ) -> bool {
224
265
fs:: read ( entry. path ( ) . join ( "CACHEDIR.TAG" ) )
225
266
. map ( |x| x. starts_with ( b"Signature: 8a477f597d28d172789f06886806bc55" ) )
@@ -256,6 +297,7 @@ impl CrateSource {
256
297
name : name. clone ( ) ,
257
298
path : dest_crate_root,
258
299
options : options. clone ( ) ,
300
+ base_url : file_link. clone ( ) ,
259
301
}
260
302
} ,
261
303
}
0 commit comments