diff --git a/.github/workflows/flake.yml b/.github/workflows/flake.yml
index a942e16ed..733ddd643 100644
--- a/.github/workflows/flake.yml
+++ b/.github/workflows/flake.yml
@@ -40,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install Nix
- uses: DeterminateSystems/nix-installer-action@v12
+ uses: DeterminateSystems/nix-installer-action@v13
- name: Setup Nix cache
uses: DeterminateSystems/magic-nix-cache-action@main
- name: Nix Flake Check
@@ -57,7 +57,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install Nix
- uses: DeterminateSystems/nix-installer-action@v12
+ uses: DeterminateSystems/nix-installer-action@v13
- name: Setup Nix cache
uses: DeterminateSystems/magic-nix-cache-action@main
- name: Nix Build
diff --git a/.github/workflows/unit-tests-bsd.yml b/.github/workflows/unit-tests-bsd.yml
index dc5544ba4..4c9a4a17a 100644
--- a/.github/workflows/unit-tests-bsd.yml
+++ b/.github/workflows/unit-tests-bsd.yml
@@ -21,29 +21,30 @@ concurrency:
cancel-in-progress: true
jobs:
- unit-tests-freebsd:
- runs-on: ubuntu-22.04
- timeout-minutes: 20
- steps:
- - uses: actions/checkout@v4
- with:
- submodules: recursive
- - name: Compile
- uses: vmactions/freebsd-vm@v1
- with:
- release: '14.0'
- usesh: true
- prepare: |
- pkg install -y rust git
- cargo install cargo-hack
- git config --global --add safe.directory /home/runner/work/eza/eza
- run: |
- set -e
- export CARGO_TERM_COLOR="always"
- export RUSTFLAGS="--deny warnings"
- cargo fmt --check
- cargo clippy -- -D warnings
- cargo hack test
+ # BUG: These tests are broken
+ # unit-tests-freebsd:
+ # runs-on: ubuntu-22.04
+ # timeout-minutes: 20
+ # steps:
+ # - uses: actions/checkout@v4
+ # with:
+ # submodules: recursive
+ # - name: Compile
+ # uses: vmactions/freebsd-vm@v1
+ # with:
+ # release: '14.1'
+ # usesh: true
+ # prepare: |
+ # pkg install -y rust git
+ # cargo install cargo-hack
+ # git config --global --add safe.directory /home/runner/work/eza/eza
+ # run: |
+ # set -e
+ # export CARGO_TERM_COLOR="always"
+ # export RUSTFLAGS="--deny warnings"
+ # cargo fmt --check
+ # cargo clippy -- -D warnings
+ # cargo hack test
unit-tests-netbsd:
runs-on: ubuntu-22.04
diff --git a/.pre-commit-config-non-nix.yaml b/.pre-commit-config-non-nix.yaml
new file mode 100644
index 000000000..97b00b074
--- /dev/null
+++ b/.pre-commit-config-non-nix.yaml
@@ -0,0 +1,15 @@
+repos:
+ - repo: local
+ hooks:
+ - id: rust-linting
+ name: Rust linting
+ description: Run rustfmt on included files
+ entry: cargo fmt --
+ types: [file, rust]
+ language: system
+ - id: rust-clippy
+ name: Rust clippy
+ description: Run clippy on included files
+ entry: cargo clippy --workspace --all-targets --all-features --
+ types: [file, rust]
+ language: system
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e1ea0f8f..c7a780fc4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,73 @@
# Changelog
+## [0.18.23] - 2024-07-25
+
+### Bug Fixes
+
+- Disable broken freebsd tests
+
+### Documentation
+
+- Clear up confusion around ls
+
+### Build
+
+- Bump log from 0.4.21 to 0.4.22
+- Bump DeterminateSystems/nix-installer-action from 12 to 13
+- Bump plist from 1.6.1 to 1.7.0
+
+## [0.18.22] - 2024-07-18
+
+### Bug Fixes
+
+- Use NaiveDateTime::from_timestamp_opt instead of panicky From impl
+
+### Features
+
+- Add non-nix pre-commit rustfmt and clippy hooks
+
+### Miscellaneous Tasks
+
+- Release eza v0.18.22
+
+### Ci
+
+- Bump FreeBSD version.
+
+## [0.18.21] - 2024-07-01
+
+### Bug Fixes
+
+- Fix missing line breaks in _eza
+
+### Miscellaneous Tasks
+
+- Release eza v0.18.21
+
+## [0.18.20] - 2024-06-27
+
+### Features
+
+- Add --no-|show-symlinks flags for filtering output
+
+### Miscellaneous Tasks
+
+- Release eza v0.18.20
+
+## [0.18.19] - 2024-06-20
+
+### Bug Fixes
+
+- Ship release binaries
+
+### Miscellaneous Tasks
+
+- Release eza v0.18.19
+
+### Build
+
+- Bump git2 from 0.18.3 to 0.19.0
+
## [0.18.18] - 2024-06-13
### Features
@@ -9,6 +77,10 @@
- Run on all features by default
- Ask for shell and terminal in bug report template
+### Miscellaneous Tasks
+
+- Release eza v0.18.18
+
### Build
- Bump unicode-width from 0.1.12 to 0.1.13
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ec3467b10..08906e65d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -44,6 +44,11 @@ Some useful commands include:
pre-commit-hooks.nix
- `just itest`: runs integration tests
+**For non-nix users,**
+There are traditional `pre-commit` hooks, which you can install with your system package manager or
+`brew|pip install pre-commit`, and run `pre-commit install -c .pre-commit-config-non-nix.yaml` in the root of the repository.
+Then these hooks will run automatically when you commit.
+
The [just](https://github.com/casey/just) command runner can be used to run some
helpful development commands, in a manner similar to `make`. Run `just --list`
to get an overview of what’s available.
diff --git a/Cargo.lock b/Cargo.lock
index d6ac77118..e5afe781d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -117,9 +117,9 @@ dependencies = [
[[package]]
name = "base64"
-version = "0.21.5"
+version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
@@ -387,7 +387,7 @@ dependencies = [
[[package]]
name = "eza"
-version = "0.18.18"
+version = "0.18.23"
dependencies = [
"ansi-width",
"chrono",
@@ -454,9 +454,9 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.18.3"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
+checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
dependencies = [
"bitflags 2.4.0",
"libc",
@@ -602,9 +602,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libgit2-sys"
-version = "0.16.2+1.7.2"
+version = "0.17.0+1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
+checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
dependencies = [
"cc",
"libc",
@@ -625,12 +625,6 @@ dependencies = [
"vcpkg",
]
-[[package]]
-name = "line-wrap"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e"
-
[[package]]
name = "linux-raw-sys"
version = "0.4.11"
@@ -648,9 +642,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.21"
+version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matches"
@@ -694,6 +688,12 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
[[package]]
name = "num-traits"
version = "0.2.14"
@@ -848,13 +848,12 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "plist"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9"
+checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64",
"indexmap",
- "line-wrap",
"quick-xml",
"time",
]
@@ -913,9 +912,9 @@ dependencies = [
[[package]]
name = "quick-xml"
-version = "0.31.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
+checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
dependencies = [
"memchr",
]
@@ -1187,12 +1186,13 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.30"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
+ "num-conv",
"powerfmt",
"serde",
"time-core",
@@ -1207,10 +1207,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.15"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
+ "num-conv",
"time-core",
]
diff --git a/Cargo.toml b/Cargo.toml
index 052ad459c..f801efb57 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ readme = "README.md"
homepage = "https://github.com/eza-community/eza"
license = "MIT"
repository = "https://github.com/eza-community/eza"
-version = "0.18.18"
+version = "0.18.23"
[package.metadata.deb]
@@ -84,7 +84,7 @@ palette = { version = "0.7.6", default-features = false, features = ["std"] }
once_cell = "1.19.0"
percent-encoding = "2.3.1"
phf = { version = "0.11.2", features = ["macros"] }
-plist = { version = "1.6.1", default-features = false }
+plist = { version = "1.7.0", default-features = false }
uutils_term_grid = "0.6.0"
terminal_size = "0.3.0"
timeago = { version = "0.4.2", default-features = false }
@@ -94,7 +94,7 @@ rayon = "1.10.0"
ansi-width = "0.1.0"
[dependencies.git2]
-version = "0.18"
+version = "0.19"
optional = true
default-features = false
diff --git a/README.md b/README.md
index 976450005..be9a5cd1a 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,7 @@
# eza
-A modern, maintained replacement for ls.
-
+A modern replacement for ls.
@@ -110,6 +109,8 @@ eza’s options are almost, but not quite, entirely unlike `ls`’s. Quick overv
- **--group-directories-first**: list directories before other files
- **-D**, **--only-dirs**: list only directories
- **-f**, **--only-files**: list only files
+- **--no-symlinks**: don't show symbolic links
+- **--show-symlinks**: explicitly show links (with `--only-dirs`, `--only-files`, to show symlinks that match the filter)
- **--git-ignore**: ignore files mentioned in `.gitignore`
- **-I**, **--ignore-glob=(globs)**: glob patterns (pipe-separated) of files to ignore
diff --git a/completions/fish/eza.fish b/completions/fish/eza.fish
index 97a579c6f..91334b583 100644
--- a/completions/fish/eza.fish
+++ b/completions/fish/eza.fish
@@ -81,6 +81,8 @@ complete -c eza -s s -l sort -d "Which field to sort by" -x -a "
complete -c eza -s I -l ignore-glob -d "Ignore files that match these glob patterns" -r
complete -c eza -s D -l only-dirs -d "List only directories"
complete -c eza -s f -l only-files -d "List only files"
+complete -c eza -l show-symlinks -d "Explicitly show symbolic links (For use with --only-dirs | --only-files)"
+complete -c eza -l no-symlinks -d "Do not show symbolic links"
# Long view options
complete -c eza -s b -l binary -d "List file sizes with binary prefixes"
diff --git a/completions/nush/eza.nu b/completions/nush/eza.nu
index 1859c0a1e..f3d42d33d 100644
--- a/completions/nush/eza.nu
+++ b/completions/nush/eza.nu
@@ -30,6 +30,8 @@ export extern "eza" [
--sort(-s) # Which field to sort by
--only-dirs(-D) # List only directories
--only-files(-f) # List only files
+ --show-symlinks # Explicitly show symbolic links (for use with --only-dirs | --only-files)
+ --no-symlinks # Do not show symbolic links
--binary(-b) # List file sizes with binary prefixes
--bytes(-B) # List file sizes in bytes, without any prefixes
--group(-g) # List each file's group
diff --git a/completions/zsh/_eza b/completions/zsh/_eza
index ed1f0c299..67cf0284d 100644
--- a/completions/zsh/_eza
+++ b/completions/zsh/_eza
@@ -33,6 +33,8 @@ __eza() {
{-A,--almost-all}"[Equivalent to --all; included for compatibility with \'ls -A\']" \
{-d,--list-dirs}"[List directories like regular files]" \
{-D,--only-dirs}"[List only directories]" \
+ --no-symlinks"[Do not show symbolic links]" \
+ --show-symlinks"[Explictly show symbolic links: for use with '--only-dirs'| '--only-files']" \
{-f,--only-files}"[List only files]" \
{-L,--level}"+[Limit the depth of recursion]" \
{-w,--width}"+[Limits column output of grid, 0 implies auto-width]" \
diff --git a/man/eza.1.md b/man/eza.1.md
index a6d43fd86..56873d9cf 100644
--- a/man/eza.1.md
+++ b/man/eza.1.md
@@ -166,6 +166,11 @@ Sort fields starting with a capital letter will sort uppercase before lowercase:
`-f`, `--only-files`
: List only files, not directories.
+`--show-symlinks`
+: Explicitly show symbolic links (when used with `--only-files` | `--only-dirs`)
+
+`--no-symlinks`
+: Do not show symbolic links
LONG VIEW OPTIONS
=================
diff --git a/src/fs/file.rs b/src/fs/file.rs
index ba2703d91..b89d10cef 100644
--- a/src/fs/file.rs
+++ b/src/fs/file.rs
@@ -13,6 +13,7 @@ use std::str;
#[cfg(unix)]
use std::sync::Mutex;
use std::sync::OnceLock;
+use std::time::SystemTime;
use chrono::prelude::*;
@@ -716,6 +717,20 @@ impl<'dir> File<'dir> {
}
}
+ /// Converts a `SystemTime` to a `NaiveDateTime` without panicking.
+ ///
+ /// Fixes #655 and #667 in `Self::modified_time`, `Self::accessed_time` and
+ /// `Self::created_time`.
+ fn systemtime_to_naivedatetime(st: SystemTime) -> Option {
+ let duration = st.duration_since(SystemTime::UNIX_EPOCH).ok()?;
+
+ // FIXME: NaiveDateTime::from_timestamp_opt is deprecated since chrono 0.4.35
+ NaiveDateTime::from_timestamp_opt(
+ duration.as_secs().try_into().ok()?,
+ (duration.as_nanos() % 1_000_000_000).try_into().ok()?,
+ )
+ }
+
/// This file’s last modified timestamp, if available on this platform.
pub fn modified_time(&self) -> Option {
if self.is_link() && self.deref_links {
@@ -726,8 +741,8 @@ impl<'dir> File<'dir> {
}
self.metadata
.modified()
- .map(|st| DateTime::::from(st).naive_utc())
.ok()
+ .and_then(Self::systemtime_to_naivedatetime)
}
/// This file’s last changed timestamp, if available on this platform.
@@ -757,8 +772,8 @@ impl<'dir> File<'dir> {
}
self.metadata
.accessed()
- .map(|st| DateTime::::from(st).naive_utc())
.ok()
+ .and_then(Self::systemtime_to_naivedatetime)
}
/// This file’s created timestamp, if available on this platform.
@@ -769,10 +784,10 @@ impl<'dir> File<'dir> {
_ => None,
};
}
- match self.metadata.created() {
- Ok(btime) => Some(DateTime::::from(btime).naive_utc()),
- Err(_) => None,
- }
+ self.metadata
+ .created()
+ .ok()
+ .and_then(Self::systemtime_to_naivedatetime)
}
/// This file’s ‘type’.
diff --git a/src/fs/filter.rs b/src/fs/filter.rs
index 162cf0ac0..2fe8a4e19 100644
--- a/src/fs/filter.rs
+++ b/src/fs/filter.rs
@@ -21,6 +21,12 @@ pub enum FileFilterFlags {
/// Whether to only show files.
OnlyFiles,
+
+ /// Whether to ignore symlinks
+ NoSymlinks,
+
+ /// Whether to explicitly show symlinks
+ ShowSymlinks,
}
/// The **file filter** processes a list of files before displaying them to
@@ -68,28 +74,47 @@ pub struct FileFilter {
/// Whether to ignore Git-ignored patterns.
pub git_ignore: GitIgnore,
+
+ /// Whether to ignore symlinks
+ pub no_symlinks: bool,
+
+ /// Whether to explicitly show symlinks
+ pub show_symlinks: bool,
}
impl FileFilter {
/// Remove every file in the given vector that does *not* pass the
/// filter predicate for files found inside a directory.
pub fn filter_child_files(&self, files: &mut Vec>) {
- use FileFilterFlags::{OnlyDirs, OnlyFiles};
+ use FileFilterFlags::{NoSymlinks, OnlyDirs, OnlyFiles, ShowSymlinks};
files.retain(|f| !self.ignore_patterns.is_ignored(&f.name));
match (
self.flags.contains(&OnlyDirs),
self.flags.contains(&OnlyFiles),
+ self.flags.contains(&NoSymlinks),
+ self.flags.contains(&ShowSymlinks),
) {
- (true, false) => {
- // On pass -'-only-dirs' flag only
+ (true, false, false, false) => {
+ // On pass '--only-dirs' flag only
+ files.retain(File::is_directory);
+ }
+ (true, false, true, false) => {
files.retain(File::is_directory);
}
- (false, true) => {
- // On pass -'-only-files' flag only
+ (true, false, false, true) => {
+ files.retain(|f| f.is_directory() || f.points_to_directory());
+ }
+ (false, true, false, false) => {
files.retain(File::is_file);
}
+ (false, true, false, true) => {
+ files.retain(|f| f.is_file() || f.is_link() && !f.points_to_directory());
+ }
+ (false, false, true, false) => {
+ files.retain(|f| !f.is_link());
+ }
_ => {}
}
}
@@ -99,7 +124,7 @@ impl FileFilter {
///
/// The rules are different for these types of files than the other
/// type because the ignore rules can be used with globbing. For
- /// example, running `exa -I='*.tmp' .vimrc` shouldn’t filter out the
+ /// example, running `exa -I='*. tmp' .vimrc` shouldn’t filter out the
/// dotfile, because it’s been directly specified. But running
/// `exa -I='*.ogg' music/*` should filter out the ogg files obtained
/// from the glob, even though the globbing is done by the shell!
@@ -249,7 +274,6 @@ impl SortField {
Self::ChangedDate => a.changed_time().cmp(&b.changed_time()),
Self::CreatedDate => a.created_time().cmp(&b.created_time()),
Self::ModifiedAge => b.modified_time().cmp(&a.modified_time()), // flip b and a
-
Self::FileType => match a.type_char().cmp(&b.type_char()) { // todo: this recomputes
Ordering::Equal => natord::compare(&a.name, &b.name),
order => order,
diff --git a/src/options/filter.rs b/src/options/filter.rs
index 745fda689..fce5a9266 100644
--- a/src/options/filter.rs
+++ b/src/options/filter.rs
@@ -18,6 +18,8 @@ impl FileFilter {
(matches.has(&flags::REVERSE)?, FFF::Reverse),
(matches.has(&flags::ONLY_DIRS)?, FFF::OnlyDirs),
(matches.has(&flags::ONLY_FILES)?, FFF::OnlyFiles),
+ (matches.has(&flags::NO_SYMLINKS)?, FFF::NoSymlinks),
+ (matches.has(&flags::SHOW_SYMLINKS)?, FFF::ShowSymlinks),
] {
if *has {
filter_flags.push(flag.clone());
@@ -27,6 +29,8 @@ impl FileFilter {
#[rustfmt::skip]
return Ok(Self {
list_dirs_first: matches.has(&flags::DIRS_FIRST)?,
+ no_symlinks: filter_flags.contains(&FFF::NoSymlinks),
+ show_symlinks: filter_flags.contains(&FFF::ShowSymlinks),
flags: filter_flags,
sort_field: SortField::deduce(matches)?,
dot_filter: DotFilter::deduce(matches)?,
diff --git a/src/options/flags.rs b/src/options/flags.rs
index 3d6d8359b..8cd538cf3 100644
--- a/src/options/flags.rs
+++ b/src/options/flags.rs
@@ -41,6 +41,8 @@ pub static GIT_IGNORE: Arg = Arg { short: None, long: "git-ignore", t
pub static DIRS_FIRST: Arg = Arg { short: None, long: "group-directories-first", takes_value: TakesValue::Forbidden };
pub static ONLY_DIRS: Arg = Arg { short: Some(b'D'), long: "only-dirs", takes_value: TakesValue::Forbidden };
pub static ONLY_FILES: Arg = Arg { short: Some(b'f'), long: "only-files", takes_value: TakesValue::Forbidden };
+pub static NO_SYMLINKS: Arg = Arg { short: None, long: "no-symlinks", takes_value: TakesValue::Forbidden };
+pub static SHOW_SYMLINKS: Arg = Arg { short: None, long: "show-symlinks", takes_value: TakesValue::Forbidden };
const SORTS: Values = &[ "name", "Name", "size", "extension",
"Extension", "modified", "changed", "accessed",
"created", "inode", "type", "none" ];
@@ -97,7 +99,7 @@ pub static ALL_ARGS: Args = Args(&[
&BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
&BLOCKSIZE, &TOTAL_SIZE, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK, &MOUNTS,
- &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &SMART_GROUP,
+ &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &SMART_GROUP, &NO_SYMLINKS, &SHOW_SYMLINKS,
&GIT, &NO_GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT,
&EXTENDED, &OCTAL, &SECURITY_CONTEXT, &STDIN, &FILE_FLAGS