Pārlūkot izejas kodu

Issues with cache filenames.

I wanted to save content as-is, but append .headers to the header
cache file.  I have that now.
Steve Thielemann 2 nedēļas atpakaļ
vecāks
revīzija
2d198e08df
2 mainītis faili ar 78 papildinājumiem un 16 dzēšanām
  1. 22 11
      src/cache.rs
  2. 56 5
      src/main.rs

+ 22 - 11
src/cache.rs

@@ -23,6 +23,7 @@ pub fn relative_to_absolute(base_url: &str, relative_href: &str) -> Result<Strin
 }
 
 /// Extract filename from the end of a URL.
+/// 
 /// If this doesn't have a usable path, convert url:
 /// * Remove https:// part
 /// * Replace / with -
@@ -183,17 +184,22 @@ impl Cache {
                 "text/html".to_string(),
                 "application/json".to_string(),
                 "text/xml".to_string(),
+                "application/x-gzip".to_string(),
             ],
-            max_size: 16 * 65536,
+            max_size: 256 * 1024 * 1024, // 256 MB
         })
     }
 
     /// Create safe filename from url for header/content files.
     pub fn url_to_basename(url: &str) -> Result<String> {
-        let filename = if url.ends_with("/") { "" } else {
+        let filename = if url.ends_with("/") {
+            ""
+        } else {
             if let Some(has_file) = url.rsplit_once("/") {
                 has_file.1
-            } else { ""}
+            } else {
+                ""
+            }
         };
 
         if filename.is_empty() {
@@ -209,7 +215,6 @@ impl Cache {
                 path.pop();
             }
             return Ok(path);
-
         }
         Ok(filename.to_string())
     }
@@ -296,10 +301,16 @@ impl Cache {
         // Don't send just yet!
         // Set some headers to see if page content has changed.
 
-        base.set_extension("header");
-        if base.exists() {
+        // This break things - it destroys the file extension (if given)
+        // base.set_extension("header");
+        let mut header_file = base.clone();
+        // Append .header to the filename.
+        let filename = header_file.file_name().unwrap().to_string_lossy().to_string() + ".header";
+        header_file.set_file_name(filename);
+
+        if header_file.exists() {
             // Ok! We have existing information.  Retrieve it.
-            let old_header = load_headermap(base.to_str().unwrap()).unwrap();
+            let old_header = load_headermap(header_file.to_str().unwrap()).unwrap();
 
             // Look for: ETag, Last-Modified
             if let Some(lastmod) = old_header.get("Last-Modified") {
@@ -320,7 +331,7 @@ impl Cache {
             // Cache hit!
 
             // println!("Cache hit! 304! {}", url);
-            base.set_extension("content");
+            // base.set_extension("content");
             let fp = std::fs::File::open(base.to_str().unwrap()).unwrap();
             return Status::Cached(fp);
         }
@@ -364,12 +375,12 @@ impl Cache {
             }
             */
 
-            let r = save_headermap(base.to_str().unwrap(), url, result.headers());
+            let r = save_headermap(header_file.to_str().unwrap(), url, result.headers());
             if r.is_err() {
-                println!("save_headermap: {}", r.unwrap_err());
+                println!("save_headermap: {} {:?}", r.unwrap_err(), header_file);
             }
 
-            base.set_extension("content");
+            // base.set_extension("content");
             let mut fp = std::fs::File::create(base.to_str().unwrap()).unwrap();
             let _ = result.copy_to(&mut fp);
             /*

+ 56 - 5
src/main.rs

@@ -1,18 +1,17 @@
-use anyhow::{bail, Context, Result};
+use anyhow::{bail, Result};
 use cache::relative_to_absolute;
 use clap::{Parser, Subcommand};
 use std::env;
 use std::fs::File;
 use std::path::PathBuf;
-use std::io::{BufRead, BufReader, Write, stdout};
+use std::io::{BufRead, BufReader}; // , Write, stdout};
 use std::process::Command;
-use url::Url;
 
 mod cache;
 
 // see reqwest/web-o/src/cache.rs for example cache
 // It restores reqwest::header::HeaderMap
-// (which allows duplicates...)
+// (which allows duplicates... and ignores case on keys)
 
 #[derive(Parser)]
 #[command(about = "Go updater")]
@@ -29,6 +28,7 @@ struct Cli {
 enum Commands {
     /// Update go
     Update {},
+    /// Display information
     Info {},
 }
 
@@ -111,6 +111,29 @@ fn download_and_save(url: &str, filename: &str) -> Result<()> {
 }
 */
 
+// URL: https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
+#[must_use]
+/// Get go version from download URL.
+fn version_from_url(url: &str, arch: &str) -> Option<String> {
+    if let Some(parts) = url.split_once(arch) {
+        if let Some(part) = parts.0.rsplit_once("/go") {
+            let part = part.1.trim_matches('.');
+            return Some(part.to_string());
+        }
+    }
+    None
+}
+
+#[must_use]
+/// Get go version from `go version` output.
+fn version_from_go(text: &str) -> Option<String> {
+    let parts : Vec<&str> = text.split(' ').collect();
+    if parts.len() == 4 {
+        return Some(parts[2].to_string().replace("go", ""))
+    }
+    None
+}
+
 /// Return just the href="<return this part>".
 #[must_use]
 fn just_href(link: &str) -> Result<String> {
@@ -175,6 +198,8 @@ fn main() -> Result<()> {
         panic!("I wasn't able to locate go.  I need `go version` to know what arch to dl.");
     }
 
+    let version = version_from_go(&go_version).unwrap();
+
     // Since I have GO_PATH, I really don't need to do `where go`...
     // $GOROOT/bin/go
 
@@ -190,11 +215,13 @@ fn main() -> Result<()> {
     let mut arch = parts.last().unwrap().to_string();
     arch = arch.replace("/", "-");
 
+    /* 
     println!("GO_PATH  {}", go_path);
     println!("GO_ROOT  {}", go_root);
     println!("version: {}", go_version);
     println!("where:   {}", go_where);
     println!("arch:    {}", arch);
+    */
 
     let cache = cache::Cache::new(cli.cache, None)?;
     // println!("Result: {:?}", get_go_downloads().await );
@@ -205,15 +232,32 @@ fn main() -> Result<()> {
         Some(Commands::Update {}) => {
             let status = cache.fetch(GO_URL);
 
+            // Check to see if file already exists AND
+            // Check version against go's version.
+
+            // Since the go.dev site doesn't allow caching or knowing when it changed...
+
             match status {
                 cache::Status::Fetched(fp) => {
                     let link = find_arch_link(&arch, &fp);
                     if let Ok(relative) = link {
                         let abs = relative_to_absolute(GO_URL, &relative).unwrap();
                         println!("URL: {}", abs);
+                        let latest_version = version_from_url(&abs, &arch);
+                        if let Some(latest) = latest_version {
+                            println!("Version: {} [have {}]", latest, version);
+                            if version != latest {
+                                let latest_status = cache.fetch(&abs);
+                                println!("Latest: {:?}", latest_status);
+                            }
+                        } else {
+                            println!("Finding version failed for string: [{}]", abs);
+                        }
                     }
                 },
                 cache::Status::Cached(fp) => {
+                    println!("(from cache)"); // I wish I could see this.
+
                     let link = find_arch_link(&arch, &fp);
                     if let Ok(relative) = link {
                         let abs = relative_to_absolute(GO_URL, &relative).unwrap();
@@ -225,7 +269,14 @@ fn main() -> Result<()> {
                 }
             }
         }
-        Some(Commands::Info {}) => {}
+        Some(Commands::Info {}) => {
+            println!("GO_PATH  {}", go_path);
+            println!("GO_ROOT  {}", go_root);
+            println!("go ver:  {}", go_version);
+            println!("version: {}", version);
+            println!("where:   {}", go_where);
+            println!("arch:    {}", arch);
+        }
         None => {
             // Display help.
             let _show_help: Cli = Cli::parse_from(["--help"]);