22
33use std:: {
44 env:: consts:: { ARCH , OS } ,
5- fs,
65 ops:: RangeInclusive ,
7- path:: { Path , PathBuf } ,
86} ;
97
10- use semver:: { Version , VersionReq } ;
11- use url:: Url ;
12-
13- use crate :: {
14- Cacher , ClangTool , DownloadError ,
15- downloader:: { download, hashing:: HashAlgorithm } ,
16- utils:: lock_path,
17- } ;
8+ use crate :: { Cacher , DownloadError } ;
189
1910/// An error that can occur while downloading a static binary.
2011#[ derive( Debug , thiserror:: Error ) ]
@@ -45,10 +36,9 @@ pub enum StaticDistDownloadError {
4536 #[ error( "Failed to parse the SHA512 sum file" ) ]
4637 Sha512Corruption ,
4738}
39+
4840const MIN_CLANG_TOOLS_VERSION : & str = env ! ( "MIN_CLANG_TOOLS_VERSION" ) ;
4941pub ( crate ) const MAX_CLANG_TOOLS_VERSION : & str = env ! ( "MAX_CLANG_TOOLS_VERSION" ) ;
50- const CLANG_TOOLS_REPO : & str = "https://github.com/cpp-linter/clang-tools-static-binaries" ;
51- const CLANG_TOOLS_TAG : & str = env ! ( "CLANG_TOOLS_TAG" ) ;
5242
5343/// A downloader that uses statically linked binary distribution files
5444/// provided by the cpp-linter team.
@@ -61,131 +51,181 @@ impl StaticDistDownloader {
6151 MIN_CLANG_TOOLS_VERSION . parse ( ) . unwrap_or ( 11 )
6252 ..=MAX_CLANG_TOOLS_VERSION . parse ( ) . unwrap_or ( 22 )
6353 }
54+ }
6455
65- /// Finds a suitable version from `req_ver` within the range of available clang tools versions.
66- ///
67- /// The available versions are determined by the `MIN_CLANG_TOOLS_VERSION` and
68- /// `MAX_CLANG_TOOLS_VERSION` environment variables (inclusive) at compile time.
69- fn find_suitable_version ( req_ver : & VersionReq ) -> Option < Version > {
70- let clang_tools_versions: RangeInclusive < u8 > = Self :: get_major_version_range ( ) ;
71- clang_tools_versions
72- . map ( |v| Version :: new ( v as u64 , 0 , 0 ) )
73- . rev ( )
74- . find ( |ver| req_ver. matches ( ver) )
56+ #[ cfg( any(
57+ // Windows support is only for x86_64 architecture (for now)
58+ all( target_os = "windows" , not( target_arch = "x86_64" ) ) ,
59+ // Linux and macOS support only x86_64 and aarch64 architectures
60+ all(
61+ any( target_os = "linux" , target_os = "macos" ) ,
62+ not( any( target_arch = "x86_64" , target_arch = "aarch64" ) )
63+ ) ,
64+ // Any OS other than Windows, Linux, or macOS is unsupported
65+ not( any( target_os = "windows" , target_os = "linux" , target_os = "macos" ) ) ,
66+ ) ) ]
67+ mod unsupported_platform {
68+ use super :: { StaticDistDownloadError , StaticDistDownloader } ;
69+ use crate :: ClangTool ;
70+ use semver:: VersionReq ;
71+ use std:: path:: PathBuf ;
72+
73+ impl StaticDistDownloader {
74+ pub async fn download_tool (
75+ _tool : & ClangTool ,
76+ _requested_version : & VersionReq ,
77+ _directory : Option < & PathBuf > ,
78+ ) -> Result < PathBuf , StaticDistDownloadError > {
79+ Err ( StaticDistDownloadError :: UnsupportedArchitecture )
80+ }
7581 }
82+ }
7683
77- /// Verifies the SHA512 checksum of the downloaded file.
78- ///
79- /// The expected checksum is extracted from another downloaded `*.sha512sum` file
80- /// (pointed to by `sha512_path`).
81- fn verify_sha512 ( file_path : & Path , sha512_path : & Path ) -> Result < ( ) , StaticDistDownloadError > {
82- let checksum_file_content = fs:: read_to_string ( sha512_path) ?;
83- let expected = checksum_file_content
84- . split ( ' ' )
85- . next ( )
86- . ok_or ( StaticDistDownloadError :: Sha512Corruption ) ?;
87- HashAlgorithm :: Sha512 ( expected. to_string ( ) ) . verify ( file_path) ?;
88- Ok ( ( ) )
89- }
84+ #[ cfg( any(
85+ // Windows support is only for x86_64 architecture (for now)
86+ all( target_os = "windows" , target_arch = "x86_64" ) ,
87+ // Linux and macOS support only x86_64 and aarch64 architectures
88+ all(
89+ any( target_os = "linux" , target_os = "macos" ) ,
90+ any( target_arch = "x86_64" , target_arch = "aarch64" )
91+ ) ,
92+ ) ) ]
93+ mod supported_platform {
94+ use std:: {
95+ fs,
96+ ops:: RangeInclusive ,
97+ path:: { Path , PathBuf } ,
98+ } ;
99+
100+ use semver:: { Version , VersionReq } ;
101+ use url:: Url ;
102+
103+ use super :: { StaticDistDownloadError , StaticDistDownloader } ;
104+ use crate :: {
105+ Cacher , ClangTool ,
106+ downloader:: { download, hashing:: HashAlgorithm } ,
107+ utils:: lock_path,
108+ } ;
109+
110+ const CLANG_TOOLS_REPO : & str = "https://github.com/cpp-linter/clang-tools-static-binaries" ;
111+ const CLANG_TOOLS_TAG : & str = env ! ( "CLANG_TOOLS_TAG" ) ;
112+
113+ impl StaticDistDownloader {
114+ /// Finds a suitable version from `req_ver` within the range of available clang tools versions.
115+ ///
116+ /// The available versions are determined by the `MIN_CLANG_TOOLS_VERSION` and
117+ /// `MAX_CLANG_TOOLS_VERSION` environment variables (inclusive) at compile time.
118+ fn find_suitable_version ( req_ver : & VersionReq ) -> Option < Version > {
119+ let clang_tools_versions: RangeInclusive < u8 > = Self :: get_major_version_range ( ) ;
120+ clang_tools_versions
121+ . map ( |v| Version :: new ( v as u64 , 0 , 0 ) )
122+ . rev ( )
123+ . find ( |ver| req_ver. matches ( ver) )
124+ }
90125
91- /// Downloads the `requested_version` of the specified `tool` from a distribution of statically linked binaries.
92- ///
93- /// The distribution is maintained at <https://github.com/cpp-linter/clang-tools-static-binaries>.
94- /// Supported platforms includes Windows, Linux, and MacOS.
95- /// Supported architectures is limited to `x86_64` (`amd64`).
96- pub async fn download_tool (
97- tool : & ClangTool ,
98- requested_version : & VersionReq ,
99- directory : Option < & PathBuf > ,
100- ) -> Result < PathBuf , StaticDistDownloadError > {
101- #[ cfg( any(
102- // Windows support is only for x86_64 architecture (for now)
103- all( target_os = "windows" , not( target_arch = "x86_64" ) ) ,
104- // Linux and macOS support only x86_64 and aarch64 architectures
105- all(
106- any( target_os = "linux" , target_os = "macos" ) ,
107- not( any( target_arch = "x86_64" , target_arch = "aarch64" ) )
108- ) ,
109- // Any OS other than Windows, Linux, or macOS is unsupported
110- not( any( target_os = "windows" , target_os = "linux" , target_os = "macos" ) ) ,
111- ) ) ]
112- return Err ( StaticDistDownloadError :: UnsupportedArchitecture ) ;
113-
114- let ver = Self :: find_suitable_version ( requested_version)
115- . ok_or ( StaticDistDownloadError :: UnsupportedVersion ) ?;
116- let ver_str = ver. major . to_string ( ) ;
117- // we already gated unsupported architectures above,
118- // so we can assume it's either x86_64 or aarch64 here
119- let arch = if cfg ! ( target_arch = "aarch64" ) {
120- "arm64"
121- } else {
122- "amd64"
123- } ;
124- let platform = if cfg ! ( target_os = "windows" ) {
125- "windows"
126- } else if cfg ! ( target_os = "macos" ) {
127- "macos"
128- } else {
129- "linux"
130- } ;
131-
132- let base_url = format ! (
133- "{CLANG_TOOLS_REPO}/releases/download/{CLANG_TOOLS_TAG}/{tool}-{ver_str}_{platform}-{arch}" ,
134- ) ;
135- let suffix = if cfg ! ( target_os = "windows" ) {
136- ".exe"
137- } else {
138- ""
139- } ;
140- let url = Url :: parse ( format ! ( "{base_url}{suffix}" ) . as_str ( ) ) ?;
141- let cache_path = Self :: get_cache_dir ( ) ;
142- let bin_name = format ! ( "{tool}-{ver_str}{suffix}" ) ;
143- let download_path = match directory {
144- None => cache_path. join ( "bin" ) . join ( & bin_name) ,
145- Some ( dir) => dir. join ( & bin_name) ,
146- } ;
147- let file_lock = lock_path ( & download_path) ?;
148- if download_path. exists ( ) {
149- log:: info!(
150- "Using cached static binary for {tool} version {ver_str} from {:?}" ,
151- download_path. to_string_lossy( )
152- ) ;
153- } else {
154- log:: info!( "Downloading static binary for {tool} version {ver_str} from {url}" ) ;
155- download ( & url, & download_path, 60 * 2 ) . await ?;
156- #[ cfg( unix) ]
157- super :: chmod_file ( & download_path, None ) ?;
126+ /// Verifies the SHA512 checksum of the downloaded file.
127+ ///
128+ /// The expected checksum is extracted from another downloaded `*.sha512sum` file
129+ /// (pointed to by `sha512_path`).
130+ fn verify_sha512 (
131+ file_path : & Path ,
132+ sha512_path : & Path ,
133+ ) -> Result < ( ) , StaticDistDownloadError > {
134+ let checksum_file_content = fs:: read_to_string ( sha512_path) ?;
135+ let expected = checksum_file_content
136+ . split ( ' ' )
137+ . next ( )
138+ . ok_or ( StaticDistDownloadError :: Sha512Corruption ) ?;
139+ HashAlgorithm :: Sha512 ( expected. to_string ( ) ) . verify ( file_path) ?;
140+ Ok ( ( ) )
158141 }
159- let sha512_cache_path = cache_path
160- . join ( "static_dist" )
161- . join ( format ! ( "{tool}-{ver_str}.sha512" ) ) ;
162- if sha512_cache_path. exists ( ) {
163- log:: info!(
164- "Using cached SHA512 checksum for {tool} version {ver_str} from {:?}" ,
165- sha512_cache_path. to_string_lossy( )
166- ) ;
167- } else {
168- let sha512_url = Url :: parse ( format ! ( "{base_url}{suffix}.sha512sum" ) . as_str ( ) ) ?;
169- log:: info!(
170- "Downloading SHA512 checksum for {tool} version {ver_str} from {sha512_url}"
142+
143+ /// Downloads the `requested_version` of the specified `tool` from a distribution of statically linked binaries.
144+ ///
145+ /// The distribution is maintained at <https://github.com/cpp-linter/clang-tools-static-binaries>.
146+ /// Supported platforms includes Windows, Linux, and MacOS.
147+ /// Supported architectures is limited to `x86_64` (`amd64`).
148+ pub async fn download_tool (
149+ tool : & ClangTool ,
150+ requested_version : & VersionReq ,
151+ directory : Option < & PathBuf > ,
152+ ) -> Result < PathBuf , StaticDistDownloadError > {
153+ let ver = Self :: find_suitable_version ( requested_version)
154+ . ok_or ( StaticDistDownloadError :: UnsupportedVersion ) ?;
155+ let ver_str = ver. major . to_string ( ) ;
156+ // we already gated unsupported architectures above,
157+ // so we can assume it's either x86_64 or aarch64 here
158+ let arch = if cfg ! ( target_arch = "aarch64" ) {
159+ "arm64"
160+ } else {
161+ "amd64"
162+ } ;
163+ let platform = if cfg ! ( target_os = "windows" ) {
164+ "windows"
165+ } else if cfg ! ( target_os = "macos" ) {
166+ "macos"
167+ } else {
168+ "linux"
169+ } ;
170+
171+ let base_url = format ! (
172+ "{CLANG_TOOLS_REPO}/releases/download/{CLANG_TOOLS_TAG}/{tool}-{ver_str}_{platform}-{arch}" ,
171173 ) ;
172- download ( & sha512_url, & sha512_cache_path, 10 ) . await ?;
174+ let suffix = if cfg ! ( target_os = "windows" ) {
175+ ".exe"
176+ } else {
177+ ""
178+ } ;
179+ let url = Url :: parse ( format ! ( "{base_url}{suffix}" ) . as_str ( ) ) ?;
180+ let cache_path = Self :: get_cache_dir ( ) ;
181+ let bin_name = format ! ( "{tool}-{ver_str}{suffix}" ) ;
182+ let download_path = match directory {
183+ None => cache_path. join ( "bin" ) . join ( & bin_name) ,
184+ Some ( dir) => dir. join ( & bin_name) ,
185+ } ;
186+ let file_lock = lock_path ( & download_path) ?;
187+ if download_path. exists ( ) {
188+ log:: info!(
189+ "Using cached static binary for {tool} version {ver_str} from {:?}" ,
190+ download_path. to_string_lossy( )
191+ ) ;
192+ } else {
193+ log:: info!( "Downloading static binary for {tool} version {ver_str} from {url}" ) ;
194+ download ( & url, & download_path, 60 * 2 ) . await ?;
195+ #[ cfg( unix) ]
196+ super :: super :: chmod_file ( & download_path, None ) ?;
197+ }
198+ let sha512_cache_path = cache_path
199+ . join ( "static_dist" )
200+ . join ( format ! ( "{tool}-{ver_str}.sha512" ) ) ;
201+ if sha512_cache_path. exists ( ) {
202+ log:: info!(
203+ "Using cached SHA512 checksum for {tool} version {ver_str} from {:?}" ,
204+ sha512_cache_path. to_string_lossy( )
205+ ) ;
206+ } else {
207+ let sha512_url = Url :: parse ( format ! ( "{base_url}{suffix}.sha512sum" ) . as_str ( ) ) ?;
208+ log:: info!(
209+ "Downloading SHA512 checksum for {tool} version {ver_str} from {sha512_url}"
210+ ) ;
211+ download ( & sha512_url, & sha512_cache_path, 10 ) . await ?;
212+ }
213+ Self :: verify_sha512 ( & download_path, & sha512_cache_path) ?;
214+ file_lock. unlock ( ) ?;
215+ Ok ( download_path)
173216 }
174- Self :: verify_sha512 ( & download_path, & sha512_cache_path) ?;
175- file_lock. unlock ( ) ?;
176- Ok ( download_path)
177217 }
178- }
179218
180- #[ cfg( test) ]
181- mod tests {
182- use super :: StaticDistDownloader ;
183- use semver:: VersionReq ;
219+ #[ cfg( test) ]
220+ mod tests {
221+ use super :: StaticDistDownloader ;
222+ use semver:: VersionReq ;
184223
185- #[ test]
186- fn find_none ( ) {
187- let req_ver = VersionReq :: parse ( "=8" ) . unwrap ( ) ;
188- let suitable_version = StaticDistDownloader :: find_suitable_version ( & req_ver) ;
189- assert_eq ! ( suitable_version, None ) ;
224+ #[ test]
225+ fn find_none ( ) {
226+ let req_ver = VersionReq :: parse ( "=8" ) . unwrap ( ) ;
227+ let suitable_version = StaticDistDownloader :: find_suitable_version ( & req_ver) ;
228+ assert_eq ! ( suitable_version, None ) ;
229+ }
190230 }
191231}
0 commit comments