1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

Merge pull request #1500 from rivy/chg.uutils-naming

Change ~ allow alternate names for `uutils`
This commit is contained in:
Roy Ivy III 2020-05-25 00:16:40 -05:00 committed by GitHub
commit 53ee25693f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 484 additions and 330 deletions

24
.editorconfig Normal file
View file

@ -0,0 +1,24 @@
# EditorConfig (is awesome): http://EditorConfig.org
# * top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,cmd,[Bb][Aa][Tt],[Cc][Mm][Dd]}]
# DOS/Win requires BAT/CMD files to have CRLF EOLNs
end_of_line = crlf
[[Mm]akefile{,.*}]
# TAB-style indentation
indent_style = tab
[*.{yml,[Yy][Mm][Ll]}]
indent_size = 2

View file

@ -24,109 +24,109 @@ test_unimplemented = []
## (common/core and Tier1) feature sets
# "feat_common_core" == baseline core set of utilities which can be built/run on most targets
feat_common_core = [
"base32",
"base64",
"basename",
"cat",
"cksum",
"comm",
"cp",
"cut",
"date",
"df",
"dircolors",
"dirname",
"echo",
"env",
"expand",
"expr",
"factor",
"false",
"fmt",
"fold",
"hashsum",
"head",
"join",
"link",
"ln",
"ls",
"mkdir",
"mktemp",
"more",
"mv",
"nl",
"od",
"paste",
"printenv",
"printf",
"ptx",
"pwd",
"readlink",
"realpath",
"relpath",
"rm",
"rmdir",
"seq",
"shred",
"shuf",
"sleep",
"sort",
"split",
"sum",
"tac",
"tail",
"tee",
"test",
"tr",
"true",
"truncate",
"tsort",
"unexpand",
"uniq",
"wc",
"yes",
"base32",
"base64",
"basename",
"cat",
"cksum",
"comm",
"cp",
"cut",
"date",
"df",
"dircolors",
"dirname",
"echo",
"env",
"expand",
"expr",
"factor",
"false",
"fmt",
"fold",
"hashsum",
"head",
"join",
"link",
"ln",
"ls",
"mkdir",
"mktemp",
"more",
"mv",
"nl",
"od",
"paste",
"printenv",
"printf",
"ptx",
"pwd",
"readlink",
"realpath",
"relpath",
"rm",
"rmdir",
"seq",
"shred",
"shuf",
"sleep",
"sort",
"split",
"sum",
"tac",
"tail",
"tee",
"test",
"tr",
"true",
"truncate",
"tsort",
"unexpand",
"uniq",
"wc",
"yes",
]
# "feat_Tier1" == expanded set of utilities which can be built/run on the usual rust "Tier 1" target platforms (ref: <https://forge.rust-lang.org/release/platform-support.html>)
feat_Tier1 = [
"feat_common_core",
#
"arch",
"hostname",
"nproc",
"sync",
"touch",
"whoami",
"feat_common_core",
#
"arch",
"hostname",
"nproc",
"sync",
"touch",
"whoami",
]
## (primary platforms) feature sets
# "feat_os_macos" == set of utilities which can be built/run on the MacOS platform
feat_os_macos = [
"feat_os_unix", ## == a modern/usual *nix platform
"feat_os_unix", ## == a modern/usual *nix platform
]
# "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms
feat_os_unix = [
"feat_Tier1",
#
"feat_require_crate_cpp",
"feat_require_unix",
"feat_require_unix_utmpx",
"feat_Tier1",
#
"feat_require_crate_cpp",
"feat_require_unix",
"feat_require_unix_utmpx",
]
# "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms
feat_os_windows = [
"feat_Tier1", ## == "feat_os_windows_legacy" + "hostname"
]
"feat_Tier1", ## == "feat_os_windows_legacy" + "hostname"
]
## (secondary platforms) feature sets
# "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat])
feat_os_unix_gnueabihf = [
"feat_Tier1",
#
"feat_require_unix",
"feat_require_unix_utmpx",
"feat_Tier1",
#
"feat_require_unix",
"feat_require_unix_utmpx",
]
# "feat_os_unix_musl" == set of utilities which can be built/run on targets binding to the "musl" library (ref: <https://musl.libc.org/about.html>)
feat_os_unix_musl = [
"feat_Tier1",
#
"feat_require_unix",
"feat_Tier1",
#
"feat_require_unix",
]
## feature sets with requirements (restricting cross-platform availability)
#
@ -134,87 +134,90 @@ feat_os_unix_musl = [
#
# "feat_require_crate_cpp" == set of utilities requiring the `cpp` crate (which fail to compile on several platforms; as of 2020-04-23)
feat_require_crate_cpp = [
"stdbuf",
"stdbuf",
]
# "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23)
feat_require_unix = [
"chgrp",
"chmod",
"chown",
"chroot",
"du",
"groups",
"hostid",
"id",
"install",
"kill",
"logname",
"mkfifo",
"mknod",
"nice",
"numfmt",
"nohup",
"pathchk",
"stat",
"timeout",
"tty",
"uname",
"unlink",
"chgrp",
"chmod",
"chown",
"chroot",
"du",
"groups",
"hostid",
"id",
"install",
"kill",
"logname",
"mkfifo",
"mknod",
"nice",
"numfmt",
"nohup",
"pathchk",
"stat",
"timeout",
"tty",
"uname",
"unlink",
]
# "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support
# * ref: <https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs?>
feat_require_unix_utmpx = [
"pinky",
"uptime",
"users",
"who",
"pinky",
"uptime",
"users",
"who",
]
## (alternate/newer/smaller platforms) feature sets
# "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: <https://fuchsia.dev>; <https://en.wikipedia.org/wiki/Google_Fuchsia>)
feat_os_unix_fuchsia = [
"feat_common_core",
#
"feat_require_crate_cpp",
#
"chgrp",
"chmod",
"chown",
"du",
"groups",
"hostid",
"install",
"logname",
"mkfifo",
"mknod",
"nice",
"pathchk",
"tty",
"uname",
"unlink",
"feat_common_core",
#
"feat_require_crate_cpp",
#
"chgrp",
"chmod",
"chown",
"du",
"groups",
"hostid",
"install",
"logname",
"mkfifo",
"mknod",
"nice",
"pathchk",
"tty",
"uname",
"unlink",
]
# "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: <https://www.redox-os.org>; <https://en.wikipedia.org/wiki/Redox_(operating_system)>)
feat_os_unix_redox = [
"feat_common_core",
#
"uname",
"chmod",
"install",
"feat_common_core",
#
"uname",
"chmod",
"install",
]
# "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP")
feat_os_windows_legacy = [
"feat_common_core",
#
"arch",
"nproc",
"sync",
"touch",
"whoami",
"feat_common_core",
#
"arch",
"nproc",
"sync",
"touch",
"whoami",
]
[workspace]
[dependencies]
uucore = "0.0.2"
lazy_static = { version="1.3" }
textwrap = { version="=0.11.0", features=["term_size"] } # !maint: [2020-05-10; rivy] unstable crate using undocumented features; pinned currently, will review
uucore = { version="0.0.2" }
# * uutils
arch = { optional=true, path="src/uu/arch" }
base32 = { optional=true, path="src/uu/base32" }
base64 = { optional=true, path="src/uu/base64" }
@ -311,11 +314,10 @@ whoami = { optional=true, path="src/uu/whoami" }
yes = { optional=true, path="src/uu/yes" }
#
# * transitive dependency via 'failure'; pin to <= v0.3.30 to avoid increasing MinSRV to v1.33.0
backtrace = ">= 0.3.3, <= 0.3.30"
_backtrace = { version=">= 0.3.3, <= 0.3.30", package="backtrace" }
[dev-dependencies]
filetime = "0.2"
lazy_static = "1.3"
libc = "0.2"
rand = "0.6"
regex = "1.0"
@ -324,8 +326,7 @@ time = "0.1"
unindent = "0.1"
[target.'cfg(unix)'.dev-dependencies]
# FIXME: this should use the normal users crate, but it conflicts with the users utility
rust-users = { git = "https://github.com/uutils/rust-users" }
rust-users = { version="0.10", package="users" }
unix_socket = "0.5.0"
[[bin]]

View file

@ -46,101 +46,101 @@ BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
# Possible programs
PROGS := \
base32 \
base64 \
basename \
cat \
cksum \
comm \
cp \
cut \
df \
dircolors \
dirname \
echo \
env \
expand \
expr \
factor \
false \
fmt \
fold \
hashsum \
head \
join \
link \
ln \
ls \
mkdir \
mktemp \
more \
mv \
nl \
numfmt \
nproc \
od \
paste \
printenv \
printf \
ptx \
pwd \
readlink \
realpath \
relpath \
rm \
rmdir \
seq \
shred \
shuf \
sleep \
sort \
split \
sum \
sync \
tac \
tail \
tee \
test \
tr \
true \
truncate \
tsort \
unexpand \
uniq \
wc \
whoami \
yes
base32 \
base64 \
basename \
cat \
cksum \
comm \
cp \
cut \
df \
dircolors \
dirname \
echo \
env \
expand \
expr \
factor \
false \
fmt \
fold \
hashsum \
head \
join \
link \
ln \
ls \
mkdir \
mktemp \
more \
mv \
nl \
numfmt \
nproc \
od \
paste \
printenv \
printf \
ptx \
pwd \
readlink \
realpath \
relpath \
rm \
rmdir \
seq \
shred \
shuf \
sleep \
sort \
split \
sum \
sync \
tac \
tail \
tee \
test \
tr \
true \
truncate \
tsort \
unexpand \
uniq \
wc \
whoami \
yes
UNIX_PROGS := \
arch \
chgrp \
chmod \
chown \
chroot \
du \
groups \
hostid \
hostname \
id \
install \
kill \
logname \
mkfifo \
mknod \
nice \
nohup \
pathchk \
pinky \
stat \
stdbuf \
timeout \
touch \
tty \
uname \
unlink \
uptime \
users \
who
arch \
chgrp \
chmod \
chown \
chroot \
du \
groups \
hostid \
hostname \
id \
install \
kill \
logname \
mkfifo \
mknod \
nice \
nohup \
pathchk \
pinky \
stat \
stdbuf \
timeout \
touch \
tty \
uname \
unlink \
uptime \
users \
who
ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS)
@ -229,7 +229,7 @@ endef
# Output names
EXES := \
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
INSTALLEES := ${EXES}
ifeq (${MULTICALL}, y)

View file

@ -36,7 +36,7 @@ set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS ""
# determine features
env_features = get_env CARGO_FEATURES
if is_empty "${env_features}"
env_features = get_env FEATURES
env_features = get_env FEATURES
end_if
if is_empty "${env_features}"
if eq "${CARGO_MAKE_RUST_TARGET_OS}" "macos"
@ -61,7 +61,7 @@ end_if
# set build flags from features
if not is_empty "${features}"
set_env CARGO_MAKE_VAR_BUILD_TEST_FEATURES "${features}"
set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS "--features ${features}"
set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS "--features ${features}"
end_if
# determine show-utils helper script
show_utils = set "util/show-utils.sh"
@ -69,15 +69,23 @@ if eq "${CARGO_MAKE_RUST_TARGET_OS}" "windows"
show_utils = set "util/show-utils.BAT"
end_if
set_env CARGO_MAKE_VAR_SHOW_UTILS "${show_utils}"
# rebuild TASK_ARGS for "--features" and package-build compatibility (using "," instead of ";")
# rebuild CARGO_MAKE_TASK_ARGS for various targets
args = set ${CARGO_MAKE_TASK_ARGS}
args = replace ${args} ";" ","
set_env CARGO_MAKE_TASK_BUILD_FEATURES_ARGS "${args}"
args = replace ${args} "," " -p"
if not is_empty "${args}"
args = set "-p${args}"
# * rebuild for 'features' target
args_features = replace ${args} ";" ","
set_env CARGO_MAKE_TASK_BUILD_FEATURES_ARGS "${args_features}"
# * rebuild for 'examples' target
args_examples = replace ${args} ";" " --example "
if is_empty "${args_examples}"
args_examples = set "--examples"
end_if
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${args}"
set_env CARGO_MAKE_TASK_BUILD_EXAMPLES_ARGS "${args_examples}"
# * rebuild for 'utils' target
args_utils = replace ${args} ";" " -p"
if not is_empty "${args_utils}"
args_utils = set "-p${args_utils}"
end_if
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${args_utils}"
'''
]
@ -88,7 +96,7 @@ description = "## *DEFAULT* Build (debug-mode) and test project"
category = "[project]"
dependencies = [
"action-build-debug",
"test-terse",
"test-terse",
]
##
@ -98,8 +106,8 @@ description = "## Build (release-mode) project"
category = "[project]"
dependencies = [
"core::pre-build",
"action-build-release",
"core::post-build",
"action-build-release",
"core::post-build",
]
[tasks.build-debug]
@ -109,18 +117,33 @@ dependencies = [
"action-build-debug",
]
[tasks.build-examples]
description = "## Build (release-mode) project example(s); usage: `cargo make (build-examples | examples | example) [EXAMPLE]...`"
category = "[project]"
dependencies = [
"core::pre-build",
"action-build-examples",
"core::post-build",
]
[tasks.build-features]
description = "## Build (with features; release-mode) project; usage: `cargo make (build-features | features) FEATURE...`"
category = "[project]"
dependencies = [
"core::pre-build",
"action-build-features",
"core::post-build",
"action-build-features",
"core::post-build",
]
[tasks.debug]
alias = "build-debug"
[tasks.example]
alias = "build-examples"
[tasks.examples]
alias = "build-examples"
[tasks.features]
alias = "build-features"
@ -162,8 +185,8 @@ description = "## Run project tests"
category = "[project]"
dependencies = [
"core::pre-test",
"core::test",
"core::post-test",
"core::test",
"core::post-test",
]
[tasks.test-terse]
@ -171,8 +194,8 @@ description = "## Run project tests (with terse/summary output)"
category = "[project]"
dependencies = [
"core::pre-test",
"action-test_quiet",
"core::post-test",
"action-test_quiet",
"core::post-test",
]
[tasks.uninstall]
@ -190,8 +213,8 @@ category = "[project]"
dependencies = [
"core::pre-build",
"action-determine-utils",
"action-build-utils",
"core::post-build",
"action-build-utils",
"core::post-build",
]
[tasks.uutil]
@ -212,6 +235,11 @@ description = "`cargo build`"
command = "cargo"
args = ["build", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )" ]
[tasks.action-build-examples]
description = "`cargo build (--examples|(--example EXAMPLE)...)`"
command = "cargo"
args = ["build", "--release", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", "${CARGO_MAKE_TASK_BUILD_EXAMPLES_ARGS}" ]
[tasks.action-build-features]
description = "`cargo build --release --features FEATURES`"
command = "cargo"

View file

@ -5,7 +5,7 @@ pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
@ -15,15 +15,15 @@ if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%

1
examples/busybox.rs Normal file
View file

@ -0,0 +1 @@
include!("../src/bin/uutils.rs");

1
examples/uu.rs Normal file
View file

@ -0,0 +1 @@
include!("../src/bin/uutils.rs");

View file

@ -1,5 +1,3 @@
#![crate_name = "uutils"]
/*
* This file is part of the uutils coreutils package.
*
@ -9,74 +7,84 @@
* file that was distributed with this source code.
*/
// spell-checker:ignore (acronyms/names) Gehring
// spell-checker:ignore (rustlang/crates) clippy concat rustlang termwidth textwrap
// spell-checker:ignore (uutils) coreutils sigpipe uucore uumain uutils
// spell-checker:ignore (shell) busybox symlinks
include!(concat!(env!("OUT_DIR"), "/uutils_crates.rs"));
use std::collections::hash_map::HashMap;
use std::io::Write;
use std::path::Path;
extern crate lazy_static;
extern crate textwrap;
extern crate uucore;
static NAME: &str = "uutils";
use lazy_static::lazy_static;
use std::collections::hash_map::HashMap;
use std::io::Write;
static VERSION: &str = env!("CARGO_PKG_VERSION");
lazy_static! {
static ref BINARY_PATH: std::path::PathBuf = {
// support symlinks by using args[0], when possible, with fallback to current_exe()
match std::env::args().next() {
Some(ref s) if !s.is_empty() => std::path::PathBuf::from(s),
_ => std::env::current_exe().unwrap(),
}
};
static ref NAME: &'static str = &*BINARY_PATH.file_stem().unwrap().to_str().unwrap();
}
include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
fn usage(cmap: &UtilityMap) {
println!("{} {}", NAME, VERSION);
println!();
println!("Usage:");
println!(" {} [util [arguments...]]\n", NAME);
println!("Currently defined functions:");
fn usage(utils: &UtilityMap) {
println!("{} {} (multi-call binary)\n", *NAME, VERSION);
println!("Usage: {} [function [arguments...]]\n", *NAME);
println!("Currently defined functions/utilities:\n");
#[allow(clippy::map_clone)]
let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
let mut utils: Vec<&str> = utils.keys().map(|&s| s).collect();
utils.sort();
for util in utils {
println!("\t{}", util);
}
let display_list = utils.join(", ");
let width = std::cmp::min(textwrap::termwidth(), 100) - 4 * 2; // (opinion/heuristic) max 100 chars wide with 4 character side indentions
println!(
"{}",
textwrap::indent(&textwrap::fill(&display_list, width), " ")
);
}
fn main() {
uucore::panic::install_sigpipe_hook();
let umap = util_map();
let utils = util_map();
let mut args: Vec<String> = uucore::args().collect();
// try binary name as util name.
let args0 = args[0].clone();
let binary = Path::new(&args0[..]);
let binary = &BINARY_PATH;
let binary_as_util = binary.file_stem().unwrap().to_str().unwrap();
if let Some(&uumain) = umap.get(binary_as_util) {
// binary name equals util name?
if let Some(&uumain) = utils.get(binary_as_util) {
std::process::exit(uumain(args));
}
if binary_as_util.ends_with("uutils")
|| binary_as_util.starts_with("uutils")
|| binary_as_util.ends_with("busybox")
|| binary_as_util.starts_with("busybox")
{
args.remove(0);
// binary name equals prefixed util name?
// * prefix/stem may be any string ending in a non-alphanumeric character
if let Some(util) = utils.keys().find(|util| {
binary_as_util.ends_with(*util)
&& !(&binary_as_util[..binary_as_util.len() - (*util).len()])
.ends_with(char::is_alphanumeric)
}) {
// prefixed util => replace 0th (aka, executable name) argument
args[0] = (*util).to_owned();
} else {
let mut found = false;
for util in umap.keys() {
if binary_as_util.ends_with(util) {
args[0] = (*util).to_owned();
found = true;
break;
}
}
if !found {
println!("{}: applet not found", binary_as_util);
std::process::exit(1);
}
// unmatched binary name => regard as multi-binary container and advance argument list
args.remove(0);
}
// try first arg as util name.
// 0th argument equals util name?
if !args.is_empty() {
let util = &args[0][..];
match umap.get(util) {
match utils.get(util) {
Some(&uumain) => {
std::process::exit(uumain(args.clone()));
}
@ -85,29 +93,29 @@ fn main() {
// see if they want help on a specific util
if args.len() >= 2 {
let util = &args[1][..];
match umap.get(util) {
match utils.get(util) {
Some(&uumain) => {
let code = uumain(vec![util.to_owned(), "--help".to_owned()]);
std::io::stdout().flush().expect("could not flush stdout");
std::process::exit(code);
}
None => {
println!("{}: applet not found", util);
println!("{}: function/utility not found", util);
std::process::exit(1);
}
}
}
usage(&umap);
usage(&utils);
std::process::exit(0);
} else {
println!("{}: applet not found", util);
println!("{}: function/utility not found", util);
std::process::exit(1);
}
}
}
} else {
// no arguments provided
usage(&umap);
usage(&utils);
std::process::exit(0);
}
}

View file

@ -128,10 +128,10 @@ Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null
or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.
Environment variables:
* EXPR_DEBUG_TOKENS=1 dump expression's tokens
* EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation
* EXPR_DEBUG_SYA_STEP=1 dump each parser step
* EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree"#
* EXPR_DEBUG_TOKENS=1 dump expression's tokens
* EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation
* EXPR_DEBUG_SYA_STEP=1 dump each parser step
* EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree"#
);
}

View file

@ -331,19 +331,19 @@ pub fn uumain(args: Vec<String>) -> i32 {
auto accept optional single/two letter suffix:
1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,
1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,
si accept optional single letter suffix:
1K = 1000, 1M = 1000000, ...
1K = 1000, 1M = 1000000, ...
iec accept optional single letter suffix:
1K = 1024, 1M = 1048576, ...
1K = 1024, 1M = 1048576, ...
iec-i accept optional two-letter suffix:
1Ki = 1024, 1Mi = 1048576, ..."
1Ki = 1024, 1Mi = 1048576, ..."
);
return 0;

View file

@ -0,0 +1,91 @@
@setLocal
@echo off
:: `test-repo-whitespace [DIR]...`
:: style inspector ~ whitespace: find nonconforming files in repository
:: Copyright (C) 2016-2020 ~ Roy Ivy III <rivy.dev@gmail.com>
:: License: MIT/Apache-2.0 (see https://opensource.org/licenses/Apache-2.0 , https://opensource.org/licenses/MIT)
:: * this software is provided for free, WITHOUT ANY EXPRESS OR IMPLIED WARRANTY (see the license for details)
:: spell-checker:ignore (shell/cmd) COMSPEC ERRORLEVEL
:: spell-checker:ignore () CTYPE POSIX Tval Tvar akefile makefile makefiles multiline
:config
set "_exclude_dir=(?i)[_.#]build|[.]git|[.]gpg|[.]vs|fixtures|vendor"
set "_exclude=(?i)[.](cache|dll|exe|gif|gz|zip)$"
:config_done
set _dp0=%~dp0.
set _nx0=%~nx0
set dirs=%*
if NOT DEFINED dirs if EXIST "%CD%\repo" ( set dirs="%CD%\repo" )
if NOT DEFINED dirs if EXIST "%_dp0%\..\.git" ( set dirs="%_dp0%\.." )
if NOT DEFINED dirs ( set "dirs=." )
set PCREGREP=pcregrep
if EXIST "%_dp0%\pcregrep.EXE" ( set "PCREGREP=%_dp0%\pcregrep.EXE" )
"%PCREGREP%" --version >NUL 2>NUL || ( echo ERR!: Missing required `pcregrep` [try `scoop install pcregrep`] 1>&2 & goto _undefined_ 2>NUL || "%COMSPEC%" /d/c exit 1 )
echo [ %dirs% ]
if /i "%LC_CTYPE%"=="posix" (set "LC_CTYPE=C") &:: `pcregrep` doesn't understand the common "POSIX", replace with the equivalent "C"
set "ERRORLEVEL="
set "ERROR="
:: 1. Test for TABs within leading whitespace (except go files makefiles)
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --exclude "(?i)[.]go$" --exclude "go[.](mod|sum)" --exclude "(GNU)?[Mm]akefile([.].*)?" --count --files-with-matches --recursive "^\s*\t" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: files found with TABs within leading whitespace [file:#lines_matched])
:: 2. Test for lines with internal TABs
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --count --files-with-matches --recursive "^.*[^\t]\t" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: files found with lines containing internal TABs [file:#lines_matched])
:: 3. Test that makefiles have ONLY initial-TAB leading whitespace
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --include "(GNU)?[Mm]akefile([.].*)?" --exclude "[.](to|y)ml$" --recursive --line-number --invert-match "^([\t]\s*\S|\S|$)" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: Makefiles found with lines having non-TAB leading whitespace [file:line_number])
:: 4. Test for non-LF line endings
set "HAVE_NonLF_ERROR="
"%PCREGREP%" --buffer-size=1M -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" -NLF --files-with-matches --multiline --recursive "\r[^\n]" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set HAVE_NonLF_ERROR=1 & echo ## files found with CR line endings)
"%PCREGREP%" --buffer-size=1M -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --exclude "(?i)\.bat$|\.cmd$" -NLF --files-with-matches --multiline --recursive "\r\n" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set HAVE_NonLF_ERROR=1 & echo ## files found with CRLF line endings)
if DEFINED HAVE_NonLF_ERROR ( set ERROR=1 & echo ERROR: files found with non-LF line endings)
:: 5. Test for files without trailing newline
:: "%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --files-without-match --multiline --recursive "\r?[\r\n]\z" %dirs%
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --files-with-matches --multiline --recursive "\z" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: files found without trailing newline)
:: 6. Test for files with lines having trailing whitespace
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --recursive --line-number "\s$" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: files found with lines having trailing whitespace [file:line_number])
:: 7. Test for files with BOM
"%PCREGREP%" -I --exclude-dir "%_exclude_dir%" --exclude "%_exclude%" --files-with-matches --multiline --recursive "\A[\xEF][\xBB][\xBF]" %dirs%
if NOT "%ERRORLEVEL%" == "1" ( set ERROR=1 & echo ERROR: files found with leading BOM)
:script_done
if NOT DEFINED ERROR (
echo success: no file errors found
)
call :#exit__title __exit_title "%COMSPEC%"
set "__exit_title=" && title %__exit_title% && set "ERRORLEVEL=" & goto _undefined_ 2>NUL || "%COMSPEC%" /d/c "exit %ERROR%"
@rem::::
@rem:: FUNCTIONS
@goto :EOF
::
:#exit__title ( ref_RETURN PATH )
:: RETURN == name of PATH
setLocal
set "_RETvar=%~1"
set "_RETval=%~2"
if NOT DEFINED _RETval ( set "_RETval=cmd" & goto :#exit__title_RETURN )
set "_RETval=%~n2"
:#exit__title_RETURN
endLocal & set %_RETvar%^=%_RETval%
goto :EOF
::