|
1 | | -use std::fs; |
| 1 | +use std::fs::{self, create_dir}; |
2 | 2 |
|
3 | 3 | use zed_extension_api::{ |
4 | 4 | self as zed, current_platform, download_file, |
@@ -138,59 +138,92 @@ impl Java { |
138 | 138 | Ok(binary_path) |
139 | 139 | } |
140 | 140 |
|
141 | | - fn lombok_jar_path( |
142 | | - &mut self, |
143 | | - language_server_id: &LanguageServerId, |
144 | | - worktree: &Worktree, |
145 | | - ) -> zed::Result<String> { |
146 | | - // Quickly return if the lombok path is already cached |
147 | | - // Expect lombok path to be validated when setting the cache so no checking is done here |
| 141 | + fn lombok_jar_path(&mut self, language_server_id: &LanguageServerId) -> zed::Result<String> { |
| 142 | + // Use cached path if exists |
| 143 | + |
148 | 144 | if let Some(path) = &self.cached_lombok_path { |
149 | | - return Ok(path.clone()); |
| 145 | + if fs::metadata(path).map_or(false, |stat| stat.is_file()) { |
| 146 | + return Ok(path.clone()); |
| 147 | + } |
150 | 148 | } |
151 | 149 |
|
152 | | - // Use lombok version specified in settings |
153 | | - // Unspecified version (None here) defaults to the latest version |
154 | | - let lombok_version = LspSettings::for_worktree(language_server_id.as_ref(), worktree)? |
155 | | - .settings |
156 | | - .and_then(|settings| { |
157 | | - settings |
158 | | - .get("lombok_version") |
159 | | - .and_then(|version| version.as_str()) |
160 | | - .map(|version_str| version_str.to_string()) |
| 150 | + // Check for latest version |
| 151 | + |
| 152 | + set_language_server_installation_status( |
| 153 | + language_server_id, |
| 154 | + &LanguageServerInstallationStatus::CheckingForUpdate, |
| 155 | + ); |
| 156 | + |
| 157 | + let tags_response_body = serde_json::from_slice::<Value>( |
| 158 | + &fetch( |
| 159 | + &HttpRequest::builder() |
| 160 | + .method(HttpMethod::Get) |
| 161 | + .url("https://api.github.com/repos/projectlombok/lombok/tags") |
| 162 | + .build()?, |
| 163 | + ) |
| 164 | + .map_err(|err| format!("failed to fetch GitHub tags: {err}"))? |
| 165 | + .body, |
| 166 | + ) |
| 167 | + .map_err(|err| format!("failed to deserialize GitHub tags response: {err}"))?; |
| 168 | + let latest_version = &tags_response_body |
| 169 | + .as_array() |
| 170 | + .and_then(|tag| { |
| 171 | + tag.first().and_then(|latest_tag| { |
| 172 | + latest_tag |
| 173 | + .get("name") |
| 174 | + .and_then(|tag_name| tag_name.as_str()) |
| 175 | + }) |
161 | 176 | }) |
162 | | - .map(|version| version.trim().to_string()); |
163 | | - |
164 | | - // Download lombok jar |
165 | | - // https://projectlombok.org/downloads/lombok.jar always points to the latest version |
166 | | - // https://projectlombok.org/downloads/lombok-{version}.jar points to the specified version |
167 | | - let (lombok_url, lombok_path) = match lombok_version { |
168 | | - Some(v) => ( |
169 | | - format!("https://projectlombok.org/downloads/lombok-{v}.jar"), |
170 | | - format!("lombok-{v}.jar"), |
171 | | - ), |
172 | | - None => ( |
173 | | - "https://projectlombok.org/downloads/lombok.jar".to_string(), |
174 | | - "lombok.jar".to_string(), |
175 | | - ), |
176 | | - }; |
177 | | - // Do not download if lombok jar already exists |
178 | | - if !std::fs::metadata(&lombok_path).map_or(false, |stat| stat.is_file()) { |
| 177 | + // Exclude 'v' at beginning |
| 178 | + .ok_or("malformed GitHub tags response")?[1..]; |
| 179 | + let prefix = "lombok"; |
| 180 | + let jar_name = format!("lombok-{latest_version}.jar"); |
| 181 | + let jar_path = format!("{prefix}/{jar_name}"); |
| 182 | + |
| 183 | + // If latest version isn't installed, |
| 184 | + if !fs::metadata(&jar_path).map_or(false, |stat| stat.is_file()) { |
| 185 | + // then download it... |
| 186 | + |
179 | 187 | set_language_server_installation_status( |
180 | 188 | language_server_id, |
181 | 189 | &LanguageServerInstallationStatus::Downloading, |
182 | 190 | ); |
183 | | - download_file(&lombok_url, &lombok_path, DownloadedFileType::Uncompressed) |
184 | | - .map_err(|e| format!("failed to download file from {lombok_url} : {e}")) |
185 | | - .inspect_err(|e| { |
186 | | - set_language_server_installation_status( |
187 | | - language_server_id, |
188 | | - &LanguageServerInstallationStatus::Failed(e.clone()), |
189 | | - ); |
190 | | - })?; |
| 191 | + create_dir(prefix).map_err(|err| err.to_string())?; |
| 192 | + download_file( |
| 193 | + &format!("https://projectlombok.org/downloads/{jar_name}"), |
| 194 | + &jar_path, |
| 195 | + DownloadedFileType::Uncompressed, |
| 196 | + )?; |
| 197 | + |
| 198 | + // ...and delete other versions |
| 199 | + |
| 200 | + // This step is expected to fail sometimes, and since we don't know |
| 201 | + // how to fix it yet, we just carry on so the user doesn't have to |
| 202 | + // restart the language server. |
| 203 | + match fs::read_dir(prefix) { |
| 204 | + Ok(entries) => { |
| 205 | + for entry in entries { |
| 206 | + match entry { |
| 207 | + Ok(entry) => { |
| 208 | + if entry.file_name().to_str() != Some(&jar_name) { |
| 209 | + if let Err(err) = fs::remove_dir_all(entry.path()) { |
| 210 | + println!("failed to remove directory entry: {err}"); |
| 211 | + } |
| 212 | + } |
| 213 | + } |
| 214 | + Err(err) => println!("failed to load directory entry: {err}"), |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | + Err(err) => println!("failed to list prefix directory: {err}"), |
| 219 | + } |
191 | 220 | } |
192 | | - self.cached_lombok_path = Some(lombok_path.to_string()); |
193 | | - Ok(lombok_path.to_string()) |
| 221 | + |
| 222 | + // else use it |
| 223 | + |
| 224 | + self.cached_lombok_path = Some(jar_path.clone()); |
| 225 | + |
| 226 | + Ok(jar_path) |
194 | 227 | } |
195 | 228 | } |
196 | 229 |
|
@@ -247,12 +280,12 @@ impl Extension for Java { |
247 | 280 | .initialization_options |
248 | 281 | .and_then(|initialization_options| { |
249 | 282 | initialization_options |
250 | | - .pointer("settings/java/jdt/ls/lombokSupport/enabled") |
| 283 | + .pointer("/settings/java/jdt/ls/lombokSupport/enabled") |
251 | 284 | .and_then(|enabled| enabled.as_bool()) |
252 | 285 | }) |
253 | 286 | .unwrap_or(false); |
254 | 287 | if lombok_enabled { |
255 | | - let lombok_jar_path = self.lombok_jar_path(language_server_id, worktree)?; |
| 288 | + let lombok_jar_path = self.lombok_jar_path(language_server_id)?; |
256 | 289 | let lombok_jar_full_path = std::env::current_dir() |
257 | 290 | .map_err(|e| format!("could not get current dir: {e}"))? |
258 | 291 | .join(&lombok_jar_path) |
|
0 commit comments