diff options
author | Dean Li <deantvv@gmail.com> | 2021-06-03 13:26:27 +0000 |
---|---|---|
committer | Dean Li <deantvv@gmail.com> | 2021-08-30 11:55:58 +0000 |
commit | 7944db336ca3ef0338369091af60aa2b15789952 (patch) | |
tree | 98d5c2a9e9a007a569710d60328e32713d832b60 | |
parent | Add CHANGELOG entry for binding behavior revamp (diff) | |
download | miniserve-7944db336ca3ef0338369091af60aa2b15789952.tar.gz miniserve-7944db336ca3ef0338369091af60aa2b15789952.zip |
Implement show symlink destination
Add option `show_symlink_info` to represent show symlink info or not.
(Default to no)
Show symlink destination after symlink symbol in directory listing
Resemble `ls -l` and also the short argument select for this feature
is also `-l`.
Basic testing is included.
Related to #499
Diffstat (limited to '')
-rw-r--r-- | data/style.scss | 16 | ||||
-rw-r--r-- | src/args.rs | 4 | ||||
-rw-r--r-- | src/config.rs | 4 | ||||
-rw-r--r-- | src/listing.rs | 20 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/renderer.rs | 31 | ||||
-rw-r--r-- | tests/serve_request.rs | 19 |
7 files changed, 69 insertions, 27 deletions
diff --git a/data/style.scss b/data/style.scss index 0a69222..7e63751 100644 --- a/data/style.scss +++ b/data/style.scss @@ -95,11 +95,18 @@ a.file:hover { color: var(--file_link_color); } +a.symlink, +a.symlink:visited { + font-weight: bold; + color: var(--symlink_color); +} + .symlink-symbol::after { content: "⇢"; display: inline-block; border: 1px solid; margin-left: 0.5rem; + margin-right: 0.5rem; border-radius: 0.2rem; padding: 0 0.1rem; } @@ -276,11 +283,6 @@ td.date-cell { color: var(--date_text_color); } -.file-entry { - display: flex; - justify-content: space-between; -} - span.size { border-radius: 1rem; background: var(--size_background_color); @@ -532,6 +534,7 @@ th span.active span { --directory_link_color_visited: #9b1985; --file_link_color: #0086b3; --file_link_color_visited: #974ec2; + --symlink_color: #ADD8E6; --table_background: #ffffff; --table_text_color: #323232; --table_header_background: #323232; @@ -578,6 +581,7 @@ th span.active span { --directory_link_color_visited: #0388f4; --file_link_color: #ea95ff; --file_link_color_visited: #a595ff; + --symlink_color: #66d9ef; --table_background: #353946; --table_text_color: #eeeeee; --table_header_background: #5294e2; @@ -624,6 +628,7 @@ th span.active span { --directory_link_color_visited: #ebc390; --file_link_color: #87d6d5; --file_link_color_visited: #a7b9ec; + --symlink_color: #11a8cd; --table_background: #4a4949; --table_text_color: #efefef; --table_header_background: #7f9f7f; @@ -670,6 +675,7 @@ th span.active span { --directory_link_color_visited: #bc39a7; --file_link_color: #a6e22e; --file_link_color_visited: #4cb936; + --symlink_color: #29b8db; --table_background: #3b3a32; --table_text_color: #f8f8f0; --table_header_background: #75715e; diff --git a/src/args.rs b/src/args.rs index 9569ca3..5467573 100644 --- a/src/args.rs +++ b/src/args.rs @@ -135,6 +135,10 @@ pub struct CliArgs { )] pub header: Vec<HeaderMap>, + /// Show symlink info + #[clap(short = 'l', long = "show-symlink-info")] + pub show_symlink_info: bool, + /// Hide version footer #[clap(short = 'F', long = "hide-version-footer")] pub hide_version_footer: bool, diff --git a/src/config.rs b/src/config.rs index e47ffc1..86fe314 100644 --- a/src/config.rs +++ b/src/config.rs @@ -95,6 +95,9 @@ pub struct MiniserveConfig { /// If specified, header will be added pub header: Vec<HeaderMap>, + /// If specified, symlink destination will be shown + pub show_symlink_info: bool, + /// If enabled, version footer is hidden pub hide_version_footer: bool, @@ -187,6 +190,7 @@ impl MiniserveConfig { dirs_first: args.dirs_first, title: args.title, header: args.header, + show_symlink_info: args.show_symlink_info, hide_version_footer: args.hide_version_footer, tls_rustls_config: tls_rustls_server_config, }) diff --git a/src/listing.rs b/src/listing.rs index 33a0342..8147113 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -84,9 +84,6 @@ pub struct Entry { /// Type of the entry pub entry_type: EntryType, - /// Entry is symlink. Not mutually exclusive with entry_type - pub is_symlink: bool, - /// URL of the entry pub link: String, @@ -95,24 +92,27 @@ pub struct Entry { /// Last modification date pub last_modification_date: Option<SystemTime>, + + /// Path of symlink pointed to + pub symlink_info: Option<String>, } impl Entry { fn new( name: String, entry_type: EntryType, - is_symlink: bool, link: String, size: Option<bytesize::ByteSize>, last_modification_date: Option<SystemTime>, + symlink_info: Option<String>, ) -> Self { Entry { name, entry_type, - is_symlink, link, size, last_modification_date, + symlink_info, } } @@ -168,6 +168,7 @@ pub fn directory_listing( zip_enabled: bool, dirs_first: bool, hide_version_footer: bool, + show_symlink_info: bool, title: Option<String>, ) -> io::Result<ServiceResponse> { use actix_web::dev::BodyEncoding; @@ -252,6 +253,11 @@ pub fn directory_listing( } res => (false, res), }; + let symlink_dest = if is_symlink && show_symlink_info { + Some(std::fs::read_link(entry.path())?) + } else { + None + }; let file_url = base .join(&utf8_percent_encode(&file_name, PATH_SEGMENT).to_string()) .to_string_lossy() @@ -271,19 +277,19 @@ pub fn directory_listing( entries.push(Entry::new( file_name, EntryType::Directory, - is_symlink, file_url, None, last_modification_date, + symlink_dest.and_then(|s| s.into_os_string().into_string().ok()), )); } else if metadata.is_file() { entries.push(Entry::new( file_name, EntryType::File, - is_symlink, file_url, Some(ByteSize::b(metadata.len())), last_modification_date, + symlink_dest.and_then(|s| s.into_os_string().into_string().ok()), )); } } else { diff --git a/src/main.rs b/src/main.rs index 882fd08..5f68cd2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -315,6 +315,7 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { let zip_enabled = conf.zip_enabled; let dirs_first = conf.dirs_first; let hide_version_footer = conf.hide_version_footer; + let cmd_enable_symlink_dest = conf.show_symlink_info; let title = conf.title.clone(); if path.is_file() { @@ -353,6 +354,7 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { zip_enabled, dirs_first, hide_version_footer, + cmd_enable_symlink_dest, title.clone(), ) }) diff --git a/src/renderer.rs b/src/renderer.rs index 901bf66..3360504 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -328,24 +328,33 @@ fn entry_row( td { p { @if entry.is_dir() { - a.directory href=(parametrized_link(&entry.link, sort_method, sort_order)) { - (entry.name) "/" - @if entry.is_symlink { + @if let Some(symlink_dest) = entry.symlink_info { + a.symlink href=(parametrized_link(&entry.link, sort_method, sort_order)) { + (entry.name) "/" span.symlink-symbol { } + a.directory {(symlink_dest) "/"} + } + }@else { + a.directory href=(parametrized_link(&entry.link, sort_method, sort_order)) { + (entry.name) "/" } } } @else if entry.is_file() { - div.file-entry { + @if let Some(symlink_dest) = entry.symlink_info { + a.symlink href=(&entry.link) { + (entry.name) + span.symlink-symbol { } + a.file {(symlink_dest)} + } + }@else { a.file href=(&entry.link) { (entry.name) - @if entry.is_symlink { - span.symlink-symbol { } - } } - @if let Some(size) = entry.size { - span.mobile-info.size { - (size) - } + } + + @if let Some(size) = entry.size { + span.mobile-info.size { + (size) } } } diff --git a/tests/serve_request.rs b/tests/serve_request.rs index bbbb7d9..ddf0471 100644 --- a/tests/serve_request.rs +++ b/tests/serve_request.rs @@ -123,10 +123,12 @@ fn serves_requests_no_hidden_files_without_flag(server: TestServer) -> Result<() } #[rstest] -#[case(true, server(&["--no-symlinks"]))] -#[case(false, server(None::<&str>))] +#[case(true, false, server(&["--no-symlinks"]))] +#[case(true, true, server(&["--no-symlinks", "--show-symlink-info"]))] +#[case(false, false, server(None::<&str>))] fn serves_requests_symlinks( #[case] no_symlinks: bool, + #[case] show_symlink_info: bool, #[case] server: TestServer, ) -> Result<(), Error> { let files = &["symlink-file.html"]; @@ -154,6 +156,9 @@ fn serves_requests_symlinks( .find(|x: &Node| x.name().unwrap_or_default() == "a" && x.text() == entry) .next(); assert_eq!(node.is_none(), no_symlinks); + if node.is_some() && show_symlink_info { + assert_eq!(node.unwrap().attr("class").unwrap(), "symlink"); + } if no_symlinks { continue; } @@ -162,9 +167,15 @@ fn serves_requests_symlinks( assert_eq!(node.attr("href").unwrap().strip_prefix("/").unwrap(), entry); reqwest::blocking::get(server.url().join(&entry)?)?.error_for_status()?; if entry.ends_with("/") { - assert_eq!(node.attr("class").unwrap(), "directory"); + let node = parsed + .find(|x: &Node| x.name().unwrap_or_default() == "a" && x.text() == DIRECTORIES[0]) + .next(); + assert_eq!(node.unwrap().attr("class").unwrap(), "directory"); } else { - assert_eq!(node.attr("class").unwrap(), "file"); + let node = parsed + .find(|x: &Node| x.name().unwrap_or_default() == "a" && x.text() == FILES[0]) + .next(); + assert_eq!(node.unwrap().attr("class").unwrap(), "file"); } } for &entry in broken { |