mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Merge pull request #1362 from Arcterus/cirrus
Test on FreeBSD using Cirrus CI and link to the Discord in the README
This commit is contained in:
commit
036dd81295
48 changed files with 1246 additions and 836 deletions
|
@ -20,13 +20,13 @@ matrix:
|
|||
|
||||
environment:
|
||||
global:
|
||||
FEATURES: "generic"
|
||||
FEATURES: "windows"
|
||||
BUILD_OPTIONS: "--no-default-features"
|
||||
TEST_OPTIONS: "--no-default-features --no-fail-fast"
|
||||
|
||||
matrix:
|
||||
# minimum version
|
||||
- CHANNEL: 1.27.0
|
||||
- CHANNEL: 1.31.0
|
||||
ARCH: i686
|
||||
ABI: msvc
|
||||
# "msvc" ABI
|
||||
|
@ -45,11 +45,11 @@ environment:
|
|||
- CHANNEL: nightly
|
||||
ARCH: i686
|
||||
ABI: msvc
|
||||
FEATURES: "generic nightly"
|
||||
FEATURES: "windows nightly"
|
||||
- CHANNEL: nightly
|
||||
ARCH: x86_64
|
||||
ABI: msvc
|
||||
FEATURES: "generic nightly"
|
||||
FEATURES: "windows nightly"
|
||||
# "gnu" ABI
|
||||
- CHANNEL: stable
|
||||
ARCH: i686
|
||||
|
|
15
.cirrus.yml
Normal file
15
.cirrus.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
freebsd_instance:
|
||||
image: freebsd-12-0-release-amd64
|
||||
|
||||
task:
|
||||
name: stable x86_64-unknown-freebsd
|
||||
setup_script:
|
||||
- pkg install -y curl gmake
|
||||
- curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
- sh rustup.sh -y
|
||||
build_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo build
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo test
|
|
@ -17,7 +17,7 @@ matrix:
|
|||
- rust: nightly
|
||||
fast_finish: true
|
||||
include:
|
||||
- rust: 1.27.0
|
||||
- rust: 1.31.0
|
||||
- rust: stable
|
||||
os: linux
|
||||
env: TEST_INSTALL=true
|
||||
|
|
745
Cargo.lock
generated
745
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,10 @@ unix = [
|
|||
"uptime",
|
||||
"users",
|
||||
"who",
|
||||
|
||||
"generic"
|
||||
]
|
||||
windows = ["generic"]
|
||||
# Feature "fuchsia" contains the exclusive list of utilities
|
||||
# that can be compiled and run on Fuchsia. Should be built
|
||||
# with --no-default-features when selecting this feature.
|
||||
|
@ -149,7 +152,7 @@ redox = [
|
|||
]
|
||||
test_unimplemented = []
|
||||
nightly = []
|
||||
default = ["generic", "unix"]
|
||||
default = ["unix"]
|
||||
|
||||
[workspace]
|
||||
|
||||
|
@ -260,6 +263,7 @@ unindent = "0.1.3"
|
|||
lazy_static = "1.3.0"
|
||||
|
||||
[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" }
|
||||
unix_socket = "0.5.0"
|
||||
|
||||
|
|
324
GNUmakefile
Normal file
324
GNUmakefile
Normal file
|
@ -0,0 +1,324 @@
|
|||
# Config options
|
||||
PROFILE ?= debug
|
||||
MULTICALL ?= n
|
||||
INSTALL ?= install
|
||||
ifneq (,$(filter install, $(MAKECMDGOALS)))
|
||||
override PROFILE:=release
|
||||
endif
|
||||
|
||||
PROFILE_CMD :=
|
||||
ifeq ($(PROFILE),release)
|
||||
PROFILE_CMD = --release
|
||||
endif
|
||||
|
||||
RM := rm -rf
|
||||
|
||||
# Binaries
|
||||
CARGO ?= cargo
|
||||
CARGOFLAGS ?=
|
||||
|
||||
# Install directories
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
BINDIR ?= /bin
|
||||
MANDIR ?= /man/man1
|
||||
|
||||
INSTALLDIR_BIN=$(DESTDIR)$(PREFIX)$(BINDIR)
|
||||
INSTALLDIR_MAN=$(DESTDIR)$(PREFIX)/share/$(MANDIR)
|
||||
$(shell test -d $(INSTALLDIR_MAN))
|
||||
ifneq ($(.SHELLSTATUS),0)
|
||||
override INSTALLDIR_MAN=$(DESTDIR)$(PREFIX)$(MANDIR)
|
||||
endif
|
||||
|
||||
#prefix to apply to uutils binary and all tool binaries
|
||||
PROG_PREFIX ?=
|
||||
|
||||
# This won't support any directory with spaces in its name, but you can just
|
||||
# make a symlink without spaces that points to the directory.
|
||||
BASEDIR ?= $(shell pwd)
|
||||
BUILDDIR := $(BASEDIR)/target/${PROFILE}
|
||||
PKG_BUILDDIR := $(BUILDDIR)/deps
|
||||
DOCSDIR := $(BASEDIR)/docs
|
||||
|
||||
BUSYBOX_ROOT := $(BASEDIR)/tmp
|
||||
BUSYBOX_VER := 1.24.1
|
||||
BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
|
||||
|
||||
# Possible programs
|
||||
PROGS := \
|
||||
base32 \
|
||||
base64 \
|
||||
basename \
|
||||
cat \
|
||||
cksum \
|
||||
comm \
|
||||
cp \
|
||||
cut \
|
||||
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
|
||||
|
||||
ifneq ($(OS),Windows_NT)
|
||||
PROGS := $(PROGS) $(UNIX_PROGS)
|
||||
endif
|
||||
|
||||
UTILS ?= $(PROGS)
|
||||
|
||||
# Programs with usable tests
|
||||
TEST_PROGS := \
|
||||
base32 \
|
||||
base64 \
|
||||
basename \
|
||||
cat \
|
||||
chgrp \
|
||||
chmod \
|
||||
chown \
|
||||
cksum \
|
||||
comm \
|
||||
cp \
|
||||
cut \
|
||||
dircolors \
|
||||
dirname \
|
||||
echo \
|
||||
env \
|
||||
expr \
|
||||
factor \
|
||||
false \
|
||||
fold \
|
||||
hashsum \
|
||||
head \
|
||||
install \
|
||||
link \
|
||||
ln \
|
||||
ls \
|
||||
mkdir \
|
||||
mktemp \
|
||||
mv \
|
||||
nl \
|
||||
numfmt \
|
||||
od \
|
||||
paste \
|
||||
pathchk \
|
||||
pinky \
|
||||
printf \
|
||||
ptx \
|
||||
pwd \
|
||||
readlink \
|
||||
realpath \
|
||||
rm \
|
||||
rmdir \
|
||||
seq \
|
||||
sort \
|
||||
split \
|
||||
stat \
|
||||
stdbuf \
|
||||
sum \
|
||||
tac \
|
||||
tail \
|
||||
test \
|
||||
touch \
|
||||
tr \
|
||||
true \
|
||||
truncate \
|
||||
tsort \
|
||||
unexpand \
|
||||
uniq \
|
||||
unlink \
|
||||
wc \
|
||||
who
|
||||
|
||||
TESTS := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(TEST_PROGS))))
|
||||
|
||||
TEST_NO_FAIL_FAST :=
|
||||
TEST_SPEC_FEATURE :=
|
||||
ifneq ($(SPEC),)
|
||||
TEST_NO_FAIL_FAST :=--no-fail-fast
|
||||
TEST_SPEC_FEATURE := test_unimplemented
|
||||
endif
|
||||
|
||||
define TEST_BUSYBOX
|
||||
test_busybox_$(1):
|
||||
(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS) $(1) )
|
||||
endef
|
||||
|
||||
# Output names
|
||||
EXES := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
|
||||
|
||||
INSTALLEES := ${EXES}
|
||||
ifeq (${MULTICALL}, y)
|
||||
INSTALLEES := ${INSTALLEES} uutils
|
||||
endif
|
||||
|
||||
# Shared library extension
|
||||
SYSTEM := $(shell uname)
|
||||
DYLIB_EXT :=
|
||||
ifeq ($(SYSTEM),Linux)
|
||||
DYLIB_EXT := so
|
||||
DYLIB_FLAGS := -shared
|
||||
endif
|
||||
ifeq ($(SYSTEM),Darwin)
|
||||
DYLIB_EXT := dylib
|
||||
DYLIB_FLAGS := -dynamiclib -undefined dynamic_lookup
|
||||
endif
|
||||
|
||||
all: build
|
||||
|
||||
do_install = $(INSTALL) ${1}
|
||||
use_default := 1
|
||||
|
||||
build-pkgs:
|
||||
ifneq (${MULTICALL}, y)
|
||||
${CARGO} build ${CARGOFLAGS} ${PROFILE_CMD} $(foreach pkg,$(EXES),-p $(pkg))
|
||||
endif
|
||||
|
||||
build-uutils:
|
||||
${CARGO} build ${CARGOFLAGS} --features "${EXES}" ${PROFILE_CMD} --no-default-features
|
||||
|
||||
build-manpages:
|
||||
cd $(DOCSDIR) && make man
|
||||
|
||||
build: build-uutils build-pkgs build-manpages
|
||||
|
||||
$(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test))))
|
||||
|
||||
test:
|
||||
${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
|
||||
|
||||
busybox-src:
|
||||
if [ ! -e $(BUSYBOX_SRC) ]; then \
|
||||
mkdir -p $(BUSYBOX_ROOT); \
|
||||
wget https://busybox.net/downloads/busybox-$(BUSYBOX_VER).tar.bz2 -P $(BUSYBOX_ROOT); \
|
||||
tar -C $(BUSYBOX_ROOT) -xf $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER).tar.bz2; \
|
||||
fi; \
|
||||
|
||||
# This is a busybox-specific config file their test suite wants to parse.
|
||||
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
|
||||
cp $< $@
|
||||
|
||||
# Test under the busybox testsuite
|
||||
$(BUILDDIR)/busybox: busybox-src build-uutils $(BUILDDIR)/.config
|
||||
cp $(BUILDDIR)/uutils $(BUILDDIR)/busybox; \
|
||||
chmod +x $@;
|
||||
|
||||
ifeq ($(EXES),)
|
||||
busytest:
|
||||
else
|
||||
busytest: $(BUILDDIR)/busybox $(addprefix test_busybox_,$(filter-out $(SKIP_UTILS),$(EXES)))
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(RM) $(BUILDDIR)
|
||||
cd $(DOCSDIR) && make clean
|
||||
|
||||
distclean: clean
|
||||
$(CARGO) clean $(CARGOFLAGS) && $(CARGO) update $(CARGOFLAGS)
|
||||
|
||||
install: build
|
||||
mkdir -p $(INSTALLDIR_BIN)
|
||||
mkdir -p $(INSTALLDIR_MAN)
|
||||
ifeq (${MULTICALL}, y)
|
||||
$(INSTALL) $(BUILDDIR)/uutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)uutils
|
||||
cd $(INSTALLDIR_BIN) && $(foreach prog, $(filter-out uutils, $(INSTALLEES)), \
|
||||
ln -fs $(PROG_PREFIX)uutils $(PROG_PREFIX)$(prog) &&) :
|
||||
cat $(DOCSDIR)/_build/man/uutils.1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)uutils.1.gz
|
||||
else
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
|
||||
endif
|
||||
$(foreach man, $(filter $(INSTALLEES), $(basename $(notdir $(wildcard $(DOCSDIR)/_build/man/*)))), \
|
||||
cat $(DOCSDIR)/_build/man/$(man).1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)$(man).1.gz &&) :
|
||||
|
||||
uninstall:
|
||||
ifeq (${MULTICALL}, y)
|
||||
rm -f $(addprefix $(INSTALLDIR_BIN)/,$(PROG_PREFIX)uutils)
|
||||
endif
|
||||
rm -f $(addprefix $(INSTALLDIR_MAN)/,$(PROG_PREFIX)uutils.1.gz)
|
||||
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
|
||||
rm -f $(addprefix $(INSTALLDIR_MAN)/$(PROG_PREFIX),$(addsuffix .1.gz,$(PROGS)))
|
||||
|
||||
.PHONY: all build build-uutils build-pkgs build-docs test distclean clean busytest install uninstall
|
329
Makefile
329
Makefile
|
@ -1,324 +1,5 @@
|
|||
# Config options
|
||||
PROFILE ?= debug
|
||||
MULTICALL ?= n
|
||||
INSTALL ?= install
|
||||
ifneq (,$(filter install, $(MAKECMDGOALS)))
|
||||
override PROFILE:=release
|
||||
endif
|
||||
|
||||
PROFILE_CMD :=
|
||||
ifeq ($(PROFILE),release)
|
||||
PROFILE_CMD = --release
|
||||
endif
|
||||
|
||||
RM := rm -rf
|
||||
|
||||
# Binaries
|
||||
CARGO ?= cargo
|
||||
CARGOFLAGS ?=
|
||||
|
||||
# Install directories
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
BINDIR ?= /bin
|
||||
MANDIR ?= /man/man1
|
||||
|
||||
INSTALLDIR_BIN=$(DESTDIR)$(PREFIX)$(BINDIR)
|
||||
INSTALLDIR_MAN=$(DESTDIR)$(PREFIX)/share/$(MANDIR)
|
||||
$(shell test -d $(INSTALLDIR_MAN))
|
||||
ifneq ($(.SHELLSTATUS),0)
|
||||
override INSTALLDIR_MAN=$(DESTDIR)$(PREFIX)$(MANDIR)
|
||||
endif
|
||||
|
||||
#prefix to apply to uutils binary and all tool binaries
|
||||
PROG_PREFIX ?=
|
||||
|
||||
# This won't support any directory with spaces in its name, but you can just
|
||||
# make a symlink without spaces that points to the directory.
|
||||
BASEDIR ?= $(shell pwd)
|
||||
BUILDDIR := $(BASEDIR)/target/${PROFILE}
|
||||
PKG_BUILDDIR := $(BUILDDIR)/deps
|
||||
DOCSDIR := $(BASEDIR)/docs
|
||||
|
||||
BUSYBOX_ROOT := $(BASEDIR)/tmp
|
||||
BUSYBOX_VER := 1.24.1
|
||||
BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
|
||||
|
||||
# Possible programs
|
||||
PROGS := \
|
||||
base32 \
|
||||
base64 \
|
||||
basename \
|
||||
cat \
|
||||
cksum \
|
||||
comm \
|
||||
cp \
|
||||
cut \
|
||||
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
|
||||
|
||||
ifneq ($(OS),Windows_NT)
|
||||
PROGS := $(PROGS) $(UNIX_PROGS)
|
||||
endif
|
||||
|
||||
UTILS ?= $(PROGS)
|
||||
|
||||
# Programs with usable tests
|
||||
TEST_PROGS := \
|
||||
base32 \
|
||||
base64 \
|
||||
basename \
|
||||
cat \
|
||||
chgrp \
|
||||
chmod \
|
||||
chown \
|
||||
cksum \
|
||||
comm \
|
||||
cp \
|
||||
cut \
|
||||
dircolors \
|
||||
dirname \
|
||||
echo \
|
||||
env \
|
||||
expr \
|
||||
factor \
|
||||
false \
|
||||
fold \
|
||||
hashsum \
|
||||
head \
|
||||
install \
|
||||
link \
|
||||
ln \
|
||||
ls \
|
||||
mkdir \
|
||||
mktemp \
|
||||
mv \
|
||||
nl \
|
||||
numfmt \
|
||||
od \
|
||||
paste \
|
||||
pathchk \
|
||||
pinky \
|
||||
printf \
|
||||
ptx \
|
||||
pwd \
|
||||
readlink \
|
||||
realpath \
|
||||
rm \
|
||||
rmdir \
|
||||
seq \
|
||||
sort \
|
||||
split \
|
||||
stat \
|
||||
stdbuf \
|
||||
sum \
|
||||
tac \
|
||||
tail \
|
||||
test \
|
||||
touch \
|
||||
tr \
|
||||
true \
|
||||
truncate \
|
||||
tsort \
|
||||
unexpand \
|
||||
uniq \
|
||||
unlink \
|
||||
wc \
|
||||
who
|
||||
|
||||
TESTS := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(TEST_PROGS))))
|
||||
|
||||
TEST_NO_FAIL_FAST :=
|
||||
TEST_SPEC_FEATURE :=
|
||||
ifneq ($(SPEC),)
|
||||
TEST_NO_FAIL_FAST :=--no-fail-fast
|
||||
TEST_SPEC_FEATURE := test_unimplemented
|
||||
endif
|
||||
|
||||
define TEST_BUSYBOX
|
||||
test_busybox_$(1):
|
||||
(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS) $(1) )
|
||||
endef
|
||||
|
||||
# Output names
|
||||
EXES := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
|
||||
|
||||
INSTALLEES := ${EXES}
|
||||
ifeq (${MULTICALL}, y)
|
||||
INSTALLEES := ${INSTALLEES} uutils
|
||||
endif
|
||||
|
||||
# Shared library extension
|
||||
SYSTEM := $(shell uname)
|
||||
DYLIB_EXT :=
|
||||
ifeq ($(SYSTEM),Linux)
|
||||
DYLIB_EXT := so
|
||||
DYLIB_FLAGS := -shared
|
||||
endif
|
||||
ifeq ($(SYSTEM),Darwin)
|
||||
DYLIB_EXT := dylib
|
||||
DYLIB_FLAGS := -dynamiclib -undefined dynamic_lookup
|
||||
endif
|
||||
|
||||
all: build
|
||||
|
||||
do_install = $(INSTALL) ${1}
|
||||
use_default := 1
|
||||
|
||||
build-pkgs:
|
||||
ifneq (${MULTICALL}, y)
|
||||
${CARGO} build ${CARGOFLAGS} ${PROFILE_CMD} $(foreach pkg,$(EXES),-p $(pkg))
|
||||
endif
|
||||
|
||||
build-uutils:
|
||||
${CARGO} build ${CARGOFLAGS} --features "${EXES}" ${PROFILE_CMD} --no-default-features
|
||||
|
||||
build-manpages:
|
||||
cd $(DOCSDIR) && make man
|
||||
|
||||
build: build-uutils build-pkgs build-manpages
|
||||
|
||||
$(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test))))
|
||||
|
||||
test:
|
||||
${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
|
||||
|
||||
busybox-src:
|
||||
if [ ! -e $(BUSYBOX_SRC) ]; then \
|
||||
mkdir -p $(BUSYBOX_ROOT); \
|
||||
wget https://busybox.net/downloads/busybox-$(BUSYBOX_VER).tar.bz2 -P $(BUSYBOX_ROOT); \
|
||||
tar -C $(BUSYBOX_ROOT) -xf $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER).tar.bz2; \
|
||||
fi; \
|
||||
|
||||
# This is a busybox-specific config file their test suite wants to parse.
|
||||
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
|
||||
cp $< $@
|
||||
|
||||
# Test under the busybox testsuite
|
||||
$(BUILDDIR)/busybox: busybox-src build-uutils $(BUILDDIR)/.config
|
||||
cp $(BUILDDIR)/uutils $(BUILDDIR)/busybox; \
|
||||
chmod +x $@;
|
||||
|
||||
ifeq ($(EXES),)
|
||||
busytest:
|
||||
else
|
||||
busytest: $(BUILDDIR)/busybox $(addprefix test_busybox_,$(filter-out $(SKIP_UTILS),$(EXES)))
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(RM) $(BUILDDIR)
|
||||
cd $(DOCSDIR) && make clean
|
||||
|
||||
distclean: clean
|
||||
$(CARGO) clean $(CARGOFLAGS) && $(CARGO) update $(CARGOFLAGS)
|
||||
|
||||
install: build
|
||||
mkdir -p $(INSTALLDIR_BIN)
|
||||
mkdir -p $(INSTALLDIR_MAN)
|
||||
ifeq (${MULTICALL}, y)
|
||||
$(INSTALL) $(BUILDDIR)/uutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)uutils
|
||||
cd $(INSTALLDIR_BIN) && $(foreach prog, $(filter-out uutils, $(INSTALLEES)), \
|
||||
ln -fs $(PROG_PREFIX)uutils $(PROG_PREFIX)$(prog) &&) :
|
||||
cat $(DOCSDIR)/_build/man/uutils.1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)uutils.1.gz
|
||||
else
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
|
||||
endif
|
||||
$(foreach man, $(filter $(INSTALLEES), $(basename $(notdir $(wildcard $(DOCSDIR)/_build/man/*)))), \
|
||||
cat $(DOCSDIR)/_build/man/$(man).1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)$(man).1.gz &&) :
|
||||
|
||||
uninstall:
|
||||
ifeq (${MULTICALL}, y)
|
||||
rm -f $(addprefix $(INSTALLDIR_BIN)/,$(PROG_PREFIX)uutils)
|
||||
endif
|
||||
rm -f $(addprefix $(INSTALLDIR_MAN)/,$(PROG_PREFIX)uutils.1.gz)
|
||||
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
|
||||
rm -f $(addprefix $(INSTALLDIR_MAN)/$(PROG_PREFIX),$(addsuffix .1.gz,$(PROGS)))
|
||||
|
||||
.PHONY: all build build-uutils build-pkgs build-docs test distclean clean busytest install uninstall
|
||||
USEGNU=gmake $*
|
||||
all:
|
||||
@$(USEGNU)
|
||||
.DEFAULT:
|
||||
@$(USEGNU)
|
||||
|
|
17
README.md
17
README.md
|
@ -1,12 +1,17 @@
|
|||
uutils coreutils
|
||||
================
|
||||
|
||||
[](https://discord.gg/wQVJbvJ)
|
||||
[](https://github.com/uutils/coreutils/blob/master/LICENSE)
|
||||
[](https://travis-ci.org/uutils/coreutils)
|
||||
[](https://ci.appveyor.com/project/Arcterus/coreutils)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils?ref=badge_shield)
|
||||
[](https://github.com/Aaronepower/tokei)
|
||||
[](https://deps.rs/repo/github/uutils/coreutils)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils?ref=badge_shield)
|
||||
|
||||
[](https://travis-ci.org/uutils/coreutils)
|
||||
[](https://ci.appveyor.com/project/Arcterus/coreutils)
|
||||
[](https://cirrus-ci.com/github/uutils/coreutils/master)
|
||||
|
||||
-----------------------------------------------
|
||||
|
||||
uutils is an attempt at writing universal (as in cross-platform) CLI
|
||||
utils in [Rust](http://www.rust-lang.org). This repo is to aggregate the GNU
|
||||
|
@ -28,15 +33,13 @@ Requirements
|
|||
|
||||
* Rust (`cargo`, `rustc`)
|
||||
* GNU Make (required to build documentation)
|
||||
* CMake (Unix; used by Oniguruma, which is required for `expr`)
|
||||
* NMake (Windows; used by Oniguruma, which is required for `expr`)
|
||||
* [Sphinx](http://www.sphinx-doc.org/) (for documentation)
|
||||
* gzip (for installing documentation)
|
||||
|
||||
### Rust Version ###
|
||||
|
||||
uutils follows Rust's release channels and is tested against stable, beta and nightly.
|
||||
The current oldest supported version of the Rust compiler is `1.27.0`.
|
||||
The current oldest supported version of the Rust compiler is `1.31.0`.
|
||||
|
||||
On both Windows and Redox, only the nightly version is tested currently.
|
||||
|
||||
|
@ -67,7 +70,7 @@ Unix-like platforms at the moment, to build on Windows, you must do the
|
|||
following:
|
||||
```bash
|
||||
# to keep debug information, compile without --release
|
||||
$ cargo build --release --no-default-features --features generic
|
||||
$ cargo build --release --no-default-features --features windows
|
||||
```
|
||||
|
||||
If you don't want to build every utility available on your platform into the
|
||||
|
|
2
build.rs
2
build.rs
|
@ -16,7 +16,7 @@ pub fn main() {
|
|||
if val == "1" && key.starts_with(feature_prefix) {
|
||||
let krate = key[feature_prefix.len()..].to_lowercase();
|
||||
match krate.as_ref() {
|
||||
"default" | "unix" | "redox" | "redox_generic" | "fuchsia" | "generic"
|
||||
"default" | "unix" | "redox" | "redox_generic" | "fuchsia" | "generic" | "windows"
|
||||
| "nightly" | "test_unimplemented" => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
|
20
docs/GNUmakefile
Normal file
20
docs/GNUmakefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = uutils
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help GNUmakefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: GNUmakefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -1,20 +1,5 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = uutils
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
USEGNU=gmake $*
|
||||
all:
|
||||
@$(USEGNU)
|
||||
.DEFAULT:
|
||||
@$(USEGNU)
|
||||
|
|
|
@ -9,7 +9,7 @@ name = "uu_arch"
|
|||
path = "arch.rs"
|
||||
|
||||
[dependencies]
|
||||
platform-info = { git = "https://github.com/uutils/platform-info" }
|
||||
platform-info = "0.0.1"
|
||||
uucore = { path = "../uucore" }
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -196,7 +196,7 @@ impl Chmoder {
|
|||
}
|
||||
};
|
||||
match self.fmode {
|
||||
Some(mode) => try!(self.change_file(fperm, mode, file, name)),
|
||||
Some(mode) => self.change_file(fperm, mode, file, name)?,
|
||||
None => {
|
||||
let cmode_unwrapped = self.cmode.clone().unwrap();
|
||||
for mode in cmode_unwrapped.split(',') {
|
||||
|
@ -209,7 +209,7 @@ impl Chmoder {
|
|||
};
|
||||
match result {
|
||||
Ok(mode) => {
|
||||
try!(self.change_file(fperm, mode, file, name));
|
||||
self.change_file(fperm, mode, file, name)?;
|
||||
fperm = mode;
|
||||
}
|
||||
Err(f) => {
|
||||
|
|
|
@ -58,7 +58,7 @@ fn cksum(fname: &str) -> io::Result<(u32, usize)> {
|
|||
let mut rd: Box<Read> = match fname {
|
||||
"-" => Box::new(stdin()),
|
||||
_ => {
|
||||
file = try!(File::open(&Path::new(fname)));
|
||||
file = File::open(&Path::new(fname))?;
|
||||
Box::new(BufReader::new(file))
|
||||
}
|
||||
};
|
||||
|
|
|
@ -117,7 +117,7 @@ fn open_file(name: &str) -> io::Result<LineReader> {
|
|||
match name {
|
||||
"-" => Ok(LineReader::Stdin(stdin())),
|
||||
_ => {
|
||||
let f = try!(File::open(&Path::new(name)));
|
||||
let f = File::open(&Path::new(name))?;
|
||||
Ok(LineReader::FileIn(BufReader::new(f)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1179,8 +1179,8 @@ pub fn localize_to_target(root: &Path, source: &Path, target: &Path) -> CopyResu
|
|||
|
||||
pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::Result<bool> {
|
||||
// We have to take symlinks and relative paths into account.
|
||||
let pathbuf1 = try!(canonicalize(p1, CanonicalizeMode::Normal));
|
||||
let pathbuf2 = try!(canonicalize(p2, CanonicalizeMode::Normal));
|
||||
let pathbuf1 = canonicalize(p1, CanonicalizeMode::Normal)?;
|
||||
let pathbuf2 = canonicalize(p2, CanonicalizeMode::Normal)?;
|
||||
|
||||
Ok(pathbuf1 == pathbuf2)
|
||||
}
|
||||
|
|
|
@ -520,7 +520,7 @@ impl<'a> WordSplit<'a> {
|
|||
impl<'a> WordSplit<'a> {
|
||||
fn new<'b>(opts: &'b FmtOptions, string: &'b str) -> WordSplit<'b> {
|
||||
// wordsplits *must* start at a non-whitespace character
|
||||
let trim_string = string.trim_left();
|
||||
let trim_string = string.trim_start();
|
||||
WordSplit {
|
||||
opts,
|
||||
string: trim_string,
|
||||
|
|
10
src/ln/ln.rs
10
src/ln/ln.rs
|
@ -269,9 +269,9 @@ fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
|
|||
if !read_yes() {
|
||||
return Ok(());
|
||||
}
|
||||
try!(fs::remove_file(dst))
|
||||
fs::remove_file(dst)?
|
||||
}
|
||||
OverwriteMode::Force => try!(fs::remove_file(dst)),
|
||||
OverwriteMode::Force => fs::remove_file(dst)?,
|
||||
};
|
||||
|
||||
backup_path = match settings.backup {
|
||||
|
@ -281,14 +281,14 @@ fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
|
|||
BackupMode::ExistingBackup => Some(existing_backup_path(dst, &settings.suffix)),
|
||||
};
|
||||
if let Some(ref p) = backup_path {
|
||||
try!(fs::rename(dst, p));
|
||||
fs::rename(dst, p)?;
|
||||
}
|
||||
}
|
||||
|
||||
if settings.symbolic {
|
||||
try!(symlink(src, dst));
|
||||
symlink(src, dst)?;
|
||||
} else {
|
||||
try!(fs::hard_link(src, dst));
|
||||
fs::hard_link(src, dst)?;
|
||||
}
|
||||
|
||||
if settings.verbose {
|
||||
|
|
|
@ -12,7 +12,7 @@ path = "ls.rs"
|
|||
getopts = "0.2.18"
|
||||
number_prefix = "0.2.8"
|
||||
term_grid = "0.1.5"
|
||||
termsize = "0.1.4"
|
||||
termsize = "0.1.6"
|
||||
time = "0.1.40"
|
||||
lazy_static = "1.0.1"
|
||||
unicode-width = "0.1.5"
|
||||
|
|
|
@ -33,15 +33,15 @@ impl fmt::Debug for FormatWriter {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&FormatWriter::IntWriter(ref p) => {
|
||||
try!(f.write_str("IntWriter:"));
|
||||
f.write_str("IntWriter:")?;
|
||||
fmt::Pointer::fmt(p, f)
|
||||
}
|
||||
&FormatWriter::FloatWriter(ref p) => {
|
||||
try!(f.write_str("FloatWriter:"));
|
||||
f.write_str("FloatWriter:")?;
|
||||
fmt::Pointer::fmt(p, f)
|
||||
}
|
||||
&FormatWriter::MultibyteWriter(ref p) => {
|
||||
try!(f.write_str("MultibyteWriter:"));
|
||||
f.write_str("MultibyteWriter:")?;
|
||||
fmt::Pointer::fmt(&(*p as *const ()), f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
|
|||
match file.read_line(&mut line) {
|
||||
Ok(0) => break,
|
||||
Ok(_) => {
|
||||
output.push_str(line.trim_right());
|
||||
output.push_str(line.trim_end());
|
||||
output.push_str(&delimiters[delim_count % delimiters.len()]);
|
||||
}
|
||||
Err(e) => crash!(1, "{}", e.to_string()),
|
||||
|
@ -118,7 +118,7 @@ fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
|
|||
eof[i] = true;
|
||||
eof_count += 1;
|
||||
}
|
||||
Ok(_) => output.push_str(line.trim_right()),
|
||||
Ok(_) => output.push_str(line.trim_end()),
|
||||
Err(e) => crash!(1, "{}", e.to_string()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -416,7 +416,7 @@ fn format_tex_line(config: &Config, word_ref: &WordRef, line: &str, reference: &
|
|||
output.push_str(&format!("\\{} ", config.macro_name));
|
||||
let all_before = if config.input_ref {
|
||||
let before = &line[0..word_ref.position];
|
||||
adjust_tex_str(before.trim().trim_left_matches(reference))
|
||||
adjust_tex_str(before.trim().trim_start_matches(reference))
|
||||
} else {
|
||||
adjust_tex_str(&line[0..word_ref.position])
|
||||
};
|
||||
|
@ -447,7 +447,7 @@ fn format_roff_line(config: &Config, word_ref: &WordRef, line: &str, reference:
|
|||
output.push_str(&format!(".{}", config.macro_name));
|
||||
let all_before = if config.input_ref {
|
||||
let before = &line[0..word_ref.position];
|
||||
adjust_roff_str(before.trim().trim_left_matches(reference))
|
||||
adjust_roff_str(before.trim().trim_start_matches(reference))
|
||||
} else {
|
||||
adjust_roff_str(&line[0..word_ref.position])
|
||||
};
|
||||
|
|
|
@ -491,24 +491,24 @@ fn do_pass(
|
|||
given_file_size: Option<u64>,
|
||||
exact: bool,
|
||||
) -> Result<(), io::Error> {
|
||||
try!(file.seek(SeekFrom::Start(0)));
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
// Use the given size or the whole file if not specified
|
||||
let size: u64 = given_file_size.unwrap_or(try!(get_file_size(path)));
|
||||
let size: u64 = given_file_size.unwrap_or(get_file_size(path)?);
|
||||
|
||||
let generator = BytesGenerator::new(size, generator_type, exact);
|
||||
|
||||
for block in generator {
|
||||
try!(file.write_all(&*block));
|
||||
file.write_all(&*block)?;
|
||||
}
|
||||
|
||||
try!(file.sync_data());
|
||||
file.sync_data()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_file_size(path: &Path) -> Result<u64, io::Error> {
|
||||
let size: u64 = try!(fs::metadata(path)).len();
|
||||
let size: u64 = fs::metadata(path)?.len();
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::
|
|||
let renamed_path: Option<PathBuf> = wipe_name(&path, verbose);
|
||||
match renamed_path {
|
||||
Some(rp) => {
|
||||
try!(fs::remove_file(rp));
|
||||
fs::remove_file(rp)?;
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
|
|
@ -21,28 +21,21 @@ pub trait BirthTime {
|
|||
|
||||
use std::fs::Metadata;
|
||||
impl BirthTime for Metadata {
|
||||
#[cfg(feature = "nightly")]
|
||||
fn pretty_birth(&self) -> String {
|
||||
self.created()
|
||||
.map(|t| t.elapsed().unwrap())
|
||||
.ok()
|
||||
.and_then(|t| t.elapsed().ok())
|
||||
.map(|e| pretty_time(e.as_secs() as i64, e.subsec_nanos() as i64))
|
||||
.unwrap_or("-".to_owned())
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
fn pretty_birth(&self) -> String {
|
||||
"-".to_owned()
|
||||
}
|
||||
#[cfg(feature = "nightly")]
|
||||
|
||||
fn birth(&self) -> String {
|
||||
self.created()
|
||||
.map(|t| t.elapsed().unwrap())
|
||||
.ok()
|
||||
.and_then(|t| t.elapsed().ok())
|
||||
.map(|e| format!("{}", e.as_secs()))
|
||||
.unwrap_or("0".to_owned())
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
fn birth(&self) -> String {
|
||||
"0".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -94,7 +87,6 @@ pub fn pretty_access(mode: mode_t) -> String {
|
|||
S_IFLNK => 'l',
|
||||
S_IFSOCK => 's',
|
||||
// TODO: Other file types
|
||||
// See coreutils/gnulib/lib/filemode.c
|
||||
_ => '?',
|
||||
});
|
||||
|
||||
|
@ -151,19 +143,19 @@ use std::convert::{AsRef, From};
|
|||
use std::error::Error;
|
||||
use std::io::Error as IOError;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android", target_os = "freebsd"))]
|
||||
use libc::statfs as Sstatfs;
|
||||
// #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
|
||||
// use self::libc::statvfs as Sstatfs;
|
||||
#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
|
||||
use libc::statvfs as Sstatfs;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android", target_os = "freebsd"))]
|
||||
use libc::statfs as statfs_fn;
|
||||
// #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
|
||||
// use self::libc::statvfs as statfs_fn;
|
||||
#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
|
||||
use libc::statvfs as statfs_fn;
|
||||
|
||||
pub trait FsMeta {
|
||||
fn fs_type(&self) -> i64;
|
||||
fn iosize(&self) -> i64;
|
||||
fn iosize(&self) -> u64;
|
||||
fn blksize(&self) -> i64;
|
||||
fn total_blocks(&self) -> u64;
|
||||
fn free_blocks(&self) -> u64;
|
||||
|
@ -171,7 +163,7 @@ pub trait FsMeta {
|
|||
fn total_fnodes(&self) -> u64;
|
||||
fn free_fnodes(&self) -> u64;
|
||||
fn fsid(&self) -> u64;
|
||||
fn namelen(&self) -> i64;
|
||||
fn namelen(&self) -> u64;
|
||||
}
|
||||
|
||||
impl FsMeta for Sstatfs {
|
||||
|
@ -193,22 +185,28 @@ impl FsMeta for Sstatfs {
|
|||
fn free_fnodes(&self) -> u64 {
|
||||
self.f_ffree as u64
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
|
||||
fn fs_type(&self) -> i64 {
|
||||
self.f_type as i64
|
||||
}
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "freebsd")))]
|
||||
fn fs_type(&self) -> i64 {
|
||||
// FIXME: statvfs doesn't have an equivalent, so we need to do something else
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn iosize(&self) -> i64 {
|
||||
self.f_frsize as i64
|
||||
fn iosize(&self) -> u64 {
|
||||
self.f_frsize as u64
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
fn iosize(&self) -> i64 {
|
||||
self.f_iosize as i64
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||
fn iosize(&self) -> u64 {
|
||||
self.f_iosize as u64
|
||||
}
|
||||
// FIXME:
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
fn iosize(&self) -> i64 {
|
||||
0
|
||||
// XXX: dunno if this is right
|
||||
#[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "linux")))]
|
||||
fn iosize(&self) -> u64 {
|
||||
self.f_bsize as u64
|
||||
}
|
||||
|
||||
// Linux, SunOS, HP-UX, 4.4BSD, FreeBSD have a system call statfs() that returns
|
||||
|
@ -217,29 +215,32 @@ impl FsMeta for Sstatfs {
|
|||
//
|
||||
// Solaris, Irix and POSIX have a system call statvfs(2) that returns a
|
||||
// struct statvfs, containing an unsigned long f_fsid
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "linux"))]
|
||||
fn fsid(&self) -> u64 {
|
||||
let f_fsid: &[u32; 2] = unsafe { transmute(&self.f_fsid) };
|
||||
(f_fsid[0] as u64) << 32 | f_fsid[1] as u64
|
||||
}
|
||||
// FIXME:
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "linux")))]
|
||||
fn fsid(&self) -> u64 {
|
||||
0
|
||||
self.f_fsid as u64
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn namelen(&self) -> i64 {
|
||||
self.f_namelen as i64
|
||||
fn namelen(&self) -> u64 {
|
||||
self.f_namelen as u64
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
fn namelen(&self) -> i64 {
|
||||
fn namelen(&self) -> u64 {
|
||||
1024
|
||||
}
|
||||
// FIXME:
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn namelen(&self) -> u64 {
|
||||
0
|
||||
self.f_namemax as u64
|
||||
}
|
||||
// XXX: should everything just use statvfs?
|
||||
#[cfg(not(any(target_os = "macos", target_os = "freebsd", target_os = "linux")))]
|
||||
fn namelen(&self) -> u64 {
|
||||
self.f_namemax as u64
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -468,7 +468,7 @@ impl Stater {
|
|||
let default_tokens = if fmtstr.is_empty() {
|
||||
Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap()
|
||||
} else {
|
||||
try!(Stater::generate_tokens(&fmtstr, use_printf))
|
||||
Stater::generate_tokens(&fmtstr, use_printf)?
|
||||
};
|
||||
let default_dev_tokens =
|
||||
Stater::generate_tokens(&Stater::default_fmt(showfs, terse, true), use_printf).unwrap();
|
||||
|
|
|
@ -5,16 +5,21 @@ use std::path::Path;
|
|||
#[path = "../../mkmain.rs"]
|
||||
mod mkmain;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
|
||||
mod platform {
|
||||
pub const DYLIB_EXT: &str = ".so";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
mod platform {
|
||||
pub const DYLIB_EXT: &str = ".dylib";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod platform {
|
||||
pub const DYLIB_EXT: &str = ".dll";
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mkmain::main();
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ enum OkMsg {
|
|||
Version,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd", target_os = "dragonflybsd"))]
|
||||
fn preload_strings() -> (&'static str, &'static str) {
|
||||
("LD_PRELOAD", "so")
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ fn preload_strings() -> (&'static str, &'static str) {
|
|||
("DYLD_LIBRARY_PATH", "dylib")
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd", target_os = "dragonflybsd", target_os = "macos")))]
|
||||
fn preload_strings() -> (&'static str, &'static str) {
|
||||
crash!(1, "Command not supported for this operating system!")
|
||||
}
|
||||
|
@ -93,8 +93,8 @@ fn print_usage(opts: &Options) {
|
|||
}
|
||||
|
||||
fn parse_size(size: &str) -> Option<u64> {
|
||||
let ext = size.trim_left_matches(|c: char| c.is_digit(10));
|
||||
let num = size.trim_right_matches(|c: char| c.is_alphabetic());
|
||||
let ext = size.trim_start_matches(|c: char| c.is_digit(10));
|
||||
let num = size.trim_end_matches(|c: char| c.is_alphabetic());
|
||||
let mut recovered = num.to_owned();
|
||||
recovered.push_str(ext);
|
||||
if recovered != size {
|
||||
|
@ -172,9 +172,9 @@ fn parse_options(
|
|||
return Ok(OkMsg::Version);
|
||||
}
|
||||
let mut modified = false;
|
||||
options.stdin = try!(check_option(&matches, "input", &mut modified).ok_or(ErrMsg::Fatal));
|
||||
options.stdout = try!(check_option(&matches, "output", &mut modified).ok_or(ErrMsg::Fatal));
|
||||
options.stderr = try!(check_option(&matches, "error", &mut modified).ok_or(ErrMsg::Fatal));
|
||||
options.stdin = check_option(&matches, "input", &mut modified).ok_or(ErrMsg::Fatal)?;
|
||||
options.stdout = check_option(&matches, "output", &mut modified).ok_or(ErrMsg::Fatal)?;
|
||||
options.stderr = check_option(&matches, "error", &mut modified).ok_or(ErrMsg::Fatal)?;
|
||||
|
||||
if matches.free.len() != 1 {
|
||||
return Err(ErrMsg::Retry);
|
||||
|
|
|
@ -68,7 +68,7 @@ fn open(name: &str) -> Result<Box<Read>> {
|
|||
match name {
|
||||
"-" => Ok(Box::new(stdin()) as Box<Read>),
|
||||
_ => {
|
||||
let f = try!(File::open(&Path::new(name)));
|
||||
let f = File::open(&Path::new(name))?;
|
||||
Ok(Box::new(f) as Box<Read>)
|
||||
}
|
||||
}
|
||||
|
|
4
src/tee/tee.rs
Executable file → Normal file
4
src/tee/tee.rs
Executable file → Normal file
|
@ -131,14 +131,14 @@ struct MultiWriter {
|
|||
impl Write for MultiWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
for writer in &mut self.writers {
|
||||
try!(writer.write_all(buf));
|
||||
writer.write_all(buf)?;
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
for writer in &mut self.writers {
|
||||
try!(writer.flush());
|
||||
writer.flush()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
2
src/tsort/tsort.rs
Executable file → Normal file
2
src/tsort/tsort.rs
Executable file → Normal file
|
@ -79,7 +79,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
let mut line = String::new();
|
||||
match reader.read_line(&mut line) {
|
||||
Ok(_) => {
|
||||
let tokens: Vec<String> = line.trim_right()
|
||||
let tokens: Vec<String> = line.trim_end()
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_owned())
|
||||
.collect();
|
||||
|
|
|
@ -10,7 +10,7 @@ path = "uname.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
platform-info = { git = "https://github.com/uutils/platform-info" }
|
||||
platform-info = "0.0.1"
|
||||
uucore = { path = "../uucore" }
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -122,7 +122,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
output.push_str(HOST_OS);
|
||||
output.push_str(" ");
|
||||
}
|
||||
println!("{}", output.trim_right());
|
||||
println!("{}", output.trim_end());
|
||||
|
||||
0
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ time = { version = "0.1.40", optional = true }
|
|||
data-encoding = { version = "^2.1", optional = true }
|
||||
libc = { version = "0.2.42", optional = true }
|
||||
wild = "2.0.1"
|
||||
nix = { version = "0.13", optional = true }
|
||||
lazy_static = { version = "1.3", optional = true }
|
||||
platform-info = { version = "0.0.1", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
termion = "1.5"
|
||||
|
@ -25,6 +28,7 @@ utmpx = ["time", "libc"]
|
|||
process = ["libc"]
|
||||
signals = []
|
||||
entries = ["libc"]
|
||||
zero-copy = ["nix", "libc", "lazy_static", "platform-info"]
|
||||
wide = []
|
||||
default = []
|
||||
|
||||
|
|
|
@ -13,6 +13,13 @@ extern crate failure;
|
|||
#[cfg(feature = "failure_derive")]
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
#[cfg(feature = "nix")]
|
||||
extern crate nix;
|
||||
#[cfg(all(feature = "lazy_static", target_os = "linux"))]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[cfg(feature = "platform-info")]
|
||||
extern crate platform_info;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -40,5 +47,8 @@ pub mod process;
|
|||
#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
|
||||
pub mod signals;
|
||||
|
||||
#[cfg(feature = "zero-copy")]
|
||||
pub mod zero_copy;
|
||||
|
||||
#[cfg(all(windows, feature = "wide"))]
|
||||
pub mod wide;
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::error::Error;
|
|||
|
||||
pub fn parse_numeric(fperm: u32, mut mode: &str) -> Result<u32, String> {
|
||||
let (op, pos) = parse_op(mode, Some('='))?;
|
||||
mode = mode[pos..].trim_left_matches('0');
|
||||
mode = mode[pos..].trim_start_matches('0');
|
||||
if mode.len() > 4 {
|
||||
Err(format!("mode is too large ({} > 7777)", mode))
|
||||
} else {
|
||||
|
|
139
src/uucore/zero_copy/mod.rs
Normal file
139
src/uucore/zero_copy/mod.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
use self::platform::*;
|
||||
|
||||
use std::io::{self, Write};
|
||||
|
||||
mod platform;
|
||||
|
||||
pub trait AsRawObject {
|
||||
fn as_raw_object(&self) -> RawObject;
|
||||
}
|
||||
|
||||
pub trait FromRawObject : Sized {
|
||||
unsafe fn from_raw_object(obj: RawObject) -> Option<Self>;
|
||||
}
|
||||
|
||||
// TODO: also make a SpliceWriter that takes an input fd and and output fd and uses splice() to
|
||||
// transfer data
|
||||
// TODO: make a TeeWriter or something that takes an input fd and two output fds and uses tee() to
|
||||
// transfer to both output fds
|
||||
|
||||
enum InnerZeroCopyWriter<T: Write + Sized> {
|
||||
Platform(PlatformZeroCopyWriter),
|
||||
Standard(T),
|
||||
}
|
||||
|
||||
impl<T: Write + Sized> Write for InnerZeroCopyWriter<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
InnerZeroCopyWriter::Platform(ref mut writer) => writer.write(buf),
|
||||
InnerZeroCopyWriter::Standard(ref mut writer) => writer.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match self {
|
||||
InnerZeroCopyWriter::Platform(ref mut writer) => writer.flush(),
|
||||
InnerZeroCopyWriter::Standard(ref mut writer) => writer.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ZeroCopyWriter<T: Write + AsRawObject + Sized> {
|
||||
/// This field is never used, but we need it to drop file descriptors
|
||||
#[allow(dead_code)]
|
||||
raw_obj_owner: Option<T>,
|
||||
|
||||
inner: InnerZeroCopyWriter<T>,
|
||||
}
|
||||
|
||||
struct TransformContainer<'a, A: Write + AsRawObject + Sized, B: Write + Sized> {
|
||||
/// This field is never used and probably could be converted into PhantomData, but might be
|
||||
/// useful for restructuring later (at the moment it's basically left over from an earlier
|
||||
/// design)
|
||||
#[allow(dead_code)]
|
||||
original: Option<&'a mut A>,
|
||||
|
||||
transformed: Option<B>,
|
||||
}
|
||||
|
||||
impl<'a, A: Write + AsRawObject + Sized, B: Write + Sized> Write for TransformContainer<'a, A, B> {
|
||||
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
|
||||
self.transformed.as_mut().unwrap().write(bytes)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.transformed.as_mut().unwrap().flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Write + AsRawObject + Sized, B: Write + Sized> AsRawObject for TransformContainer<'a, A, B> {
|
||||
fn as_raw_object(&self) -> RawObject {
|
||||
panic!("Test should never be used")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Write + AsRawObject + Sized> ZeroCopyWriter<T> {
|
||||
pub fn new(writer: T) -> Self {
|
||||
let raw_obj = writer.as_raw_object();
|
||||
match unsafe { PlatformZeroCopyWriter::new(raw_obj) } {
|
||||
Ok(inner) => {
|
||||
ZeroCopyWriter {
|
||||
raw_obj_owner: Some(writer),
|
||||
inner: InnerZeroCopyWriter::Platform(inner),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// creating the splice writer failed for whatever reason, so just make a default
|
||||
// writer
|
||||
ZeroCopyWriter {
|
||||
raw_obj_owner: None,
|
||||
inner: InnerZeroCopyWriter::Standard(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_default<'a: 'b, 'b, F, W>(writer: &'a mut T, func: F) -> ZeroCopyWriter<impl Write + AsRawObject + Sized + 'b>
|
||||
where
|
||||
F: Fn(&'a mut T) -> W,
|
||||
W: Write + Sized + 'b,
|
||||
{
|
||||
let raw_obj = writer.as_raw_object();
|
||||
match unsafe { PlatformZeroCopyWriter::new(raw_obj) } {
|
||||
Ok(inner) => {
|
||||
ZeroCopyWriter {
|
||||
raw_obj_owner: Some(TransformContainer { original: Some(writer), transformed: None, }),
|
||||
inner: InnerZeroCopyWriter::Platform(inner),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// XXX: should func actually consume writer and leave it up to the user to save the value?
|
||||
// maybe provide a default stdin method then? in some cases it would make more sense for the
|
||||
// value to be consumed
|
||||
let real_writer = func(writer);
|
||||
ZeroCopyWriter {
|
||||
raw_obj_owner: None,
|
||||
inner: InnerZeroCopyWriter::Standard(TransformContainer { original: None, transformed: Some(real_writer) }),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: unsure how to get something like this working without allocating, so not providing it
|
||||
/*pub fn stdout() -> ZeroCopyWriter<impl Write + AsRawObject + Sized> {
|
||||
let mut stdout = io::stdout();
|
||||
ZeroCopyWriter::with_default(&mut stdout, |stdout| {
|
||||
stdout.lock()
|
||||
})
|
||||
}*/
|
||||
}
|
||||
|
||||
impl<T: Write + AsRawObject + Sized> Write for ZeroCopyWriter<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.inner.flush()
|
||||
}
|
||||
}
|
21
src/uucore/zero_copy/platform/default.rs
Normal file
21
src/uucore/zero_copy/platform/default.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::zero_copy::RawObject;
|
||||
|
||||
use std::io::{self, Write};
|
||||
|
||||
pub struct PlatformZeroCopyWriter;
|
||||
|
||||
impl PlatformZeroCopyWriter {
|
||||
pub unsafe fn new(_obj: RawObject) -> Result<Self, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for PlatformZeroCopyWriter {
|
||||
fn write(&mut self, _bytes: &[u8]) -> io::Result<usize> {
|
||||
panic!("should never occur")
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
panic!("should never occur")
|
||||
}
|
||||
}
|
105
src/uucore/zero_copy/platform/linux.rs
Normal file
105
src/uucore/zero_copy/platform/linux.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::io::{self, Write};
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
use libc::{O_APPEND, S_IFIFO, S_IFREG};
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{fcntl, splice, vmsplice, FcntlArg, SpliceFFlags};
|
||||
use nix::sys::uio::IoVec;
|
||||
use nix::sys::stat::{fstat, FileStat};
|
||||
use nix::unistd::pipe;
|
||||
use platform_info::{Uname, PlatformInfo};
|
||||
|
||||
use crate::zero_copy::{FromRawObject, RawObject};
|
||||
|
||||
lazy_static! {
|
||||
static ref IN_WSL: bool = {
|
||||
let info = PlatformInfo::new().unwrap();
|
||||
info.release().contains("Microsoft")
|
||||
};
|
||||
}
|
||||
|
||||
pub struct PlatformZeroCopyWriter {
|
||||
raw_obj: RawObject,
|
||||
read_pipe: RawFd,
|
||||
write_pipe: RawFd,
|
||||
write_fn: fn(&mut PlatformZeroCopyWriter, &[IoVec<&[u8]>], usize) -> io::Result<usize>,
|
||||
}
|
||||
|
||||
impl PlatformZeroCopyWriter {
|
||||
pub unsafe fn new(raw_obj: RawObject) -> nix::Result<Self> {
|
||||
if *IN_WSL {
|
||||
// apparently WSL hasn't implemented vmsplice(), causing writes to fail
|
||||
// thus, we will just say zero-copy doesn't work there rather than working
|
||||
// around it
|
||||
return Err(nix::Error::from(Errno::EOPNOTSUPP))
|
||||
}
|
||||
|
||||
let stat_info: FileStat = fstat(raw_obj)?;
|
||||
let access_mode: libc::c_int = fcntl(raw_obj, FcntlArg::F_GETFL)?;
|
||||
|
||||
let is_regular = (stat_info.st_mode & S_IFREG) != 0;
|
||||
let is_append = (access_mode & O_APPEND) != 0;
|
||||
let is_fifo = (stat_info.st_mode & S_IFIFO) != 0;
|
||||
|
||||
if is_regular && !is_append {
|
||||
let (read_pipe, write_pipe) = pipe()?;
|
||||
|
||||
Ok(PlatformZeroCopyWriter {
|
||||
raw_obj,
|
||||
read_pipe,
|
||||
write_pipe,
|
||||
write_fn: write_regular,
|
||||
})
|
||||
} else if is_fifo {
|
||||
Ok(PlatformZeroCopyWriter {
|
||||
raw_obj,
|
||||
read_pipe: Default::default(),
|
||||
write_pipe: Default::default(),
|
||||
write_fn: write_fifo,
|
||||
})
|
||||
} else {
|
||||
// FIXME: how to error?
|
||||
Err(nix::Error::from(Errno::UnknownErrno))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawObject for PlatformZeroCopyWriter {
|
||||
unsafe fn from_raw_object(obj: RawObject) -> Option<Self> {
|
||||
PlatformZeroCopyWriter::new(obj).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for PlatformZeroCopyWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let iovec = &[IoVec::from_slice(buf)];
|
||||
|
||||
let func = self.write_fn;
|
||||
func(self, iovec, buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
// XXX: not sure if we need anything else
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_regular(writer: &mut PlatformZeroCopyWriter, iovec: &[IoVec<&[u8]>], len: usize) -> io::Result<usize> {
|
||||
vmsplice(writer.write_pipe, iovec, SpliceFFlags::empty())
|
||||
.and_then(|_|
|
||||
splice(
|
||||
writer.read_pipe,
|
||||
None,
|
||||
writer.raw_obj,
|
||||
None,
|
||||
len,
|
||||
SpliceFFlags::empty()
|
||||
)
|
||||
)
|
||||
.map_err(|_| io::Error::last_os_error())
|
||||
}
|
||||
|
||||
fn write_fifo(writer: &mut PlatformZeroCopyWriter, iovec: &[IoVec<&[u8]>], _len: usize) -> io::Result<usize> {
|
||||
vmsplice(writer.raw_obj, iovec, SpliceFFlags::empty())
|
||||
.map_err(|_| io::Error::last_os_error())
|
||||
}
|
21
src/uucore/zero_copy/platform/mod.rs
Normal file
21
src/uucore/zero_copy/platform/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
#[cfg(unix)]
|
||||
pub use self::unix::*;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub use self::linux::*;
|
||||
#[cfg(windows)]
|
||||
pub use self::windows::*;
|
||||
|
||||
// Add any operating systems we support here
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub use self::default::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux;
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
|
||||
// Add any operating systems we support here
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
mod default;
|
18
src/uucore/zero_copy/platform/unix.rs
Normal file
18
src/uucore/zero_copy/platform/unix.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
use crate::zero_copy::{AsRawObject, FromRawObject};
|
||||
|
||||
pub type RawObject = RawFd;
|
||||
|
||||
impl<T: AsRawFd> AsRawObject for T {
|
||||
fn as_raw_object(&self) -> RawObject {
|
||||
self.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: check if this works right
|
||||
impl<T: FromRawFd> FromRawObject for T {
|
||||
unsafe fn from_raw_object(obj: RawObject) -> Option<Self> {
|
||||
Some(T::from_raw_fd(obj))
|
||||
}
|
||||
}
|
19
src/uucore/zero_copy/platform/windows.rs
Normal file
19
src/uucore/zero_copy/platform/windows.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle};
|
||||
|
||||
use crate::zero_copy::{AsRawObject, FromRawObject};
|
||||
|
||||
pub type RawObject = RawHandle;
|
||||
|
||||
impl<T: AsRawHandle> AsRawObject for T {
|
||||
fn as_raw_object(&self) -> RawObject {
|
||||
self.as_raw_handle()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromRawHandle> FromRawObject for T {
|
||||
unsafe fn from_raw_object(obj: RawObject) -> Option<Self> {
|
||||
Some(T::from_raw_handle(obj))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: see if there's some zero-copy stuff in Windows
|
|
@ -144,7 +144,7 @@ fn wc(files: Vec<String>, settings: &Settings) -> StdResult<(), i32> {
|
|||
let mut max_width: usize = 0;
|
||||
|
||||
for path in &files {
|
||||
let mut reader = try!(open(&path[..]));
|
||||
let mut reader = open(&path[..])?;
|
||||
|
||||
let mut line_count: usize = 0;
|
||||
let mut word_count: usize = 0;
|
||||
|
|
|
@ -31,7 +31,7 @@ static LONG_HELP: &str = "
|
|||
-m only hostname and user associated with stdin
|
||||
-p, --process print active processes spawned by init
|
||||
-q, --count all login names and number of users logged on
|
||||
-r, --runlevel print current runlevel
|
||||
-r, --runlevel print current runlevel (not available on BSDs)
|
||||
-s, --short print only name, line, and time (default)
|
||||
-t, --time print last system clock change
|
||||
-T, -w, --mesg add user's message status as +, - or ?
|
||||
|
@ -60,6 +60,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
"count",
|
||||
"all login names and number of users logged on",
|
||||
);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux", target_os = "android"))]
|
||||
opts.optflag("r", "runlevel", "print current runlevel");
|
||||
opts.optflag("s", "short", "print only name, line, and time (default)");
|
||||
opts.optflag("t", "time", "print last system clock change");
|
||||
|
@ -281,7 +282,7 @@ fn current_tty() -> String {
|
|||
if !res.is_null() {
|
||||
CStr::from_ptr(res as *const _)
|
||||
.to_string_lossy()
|
||||
.trim_left_matches("/dev/")
|
||||
.trim_start_matches("/dev/")
|
||||
.to_owned()
|
||||
} else {
|
||||
"".to_owned()
|
||||
|
@ -291,6 +292,17 @@ fn current_tty() -> String {
|
|||
|
||||
impl Who {
|
||||
fn exec(&mut self) {
|
||||
let run_level_chk = |record: i16| {
|
||||
#[allow(unused_assignments)]
|
||||
let mut res = false;
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux", target_os = "android"))]
|
||||
{
|
||||
res = record == utmpx::RUN_LVL;
|
||||
}
|
||||
res
|
||||
};
|
||||
|
||||
let f = if self.args.len() == 1 {
|
||||
self.args[0].as_ref()
|
||||
} else {
|
||||
|
@ -321,7 +333,7 @@ impl Who {
|
|||
if !self.my_line_only || cur_tty == ut.tty_device() {
|
||||
if self.need_users && ut.is_user_process() {
|
||||
self.print_user(&ut);
|
||||
} else if self.need_runlevel && ut.record_type() == utmpx::RUN_LVL {
|
||||
} else if self.need_runlevel && run_level_chk(ut.record_type()) {
|
||||
self.print_runlevel(&ut);
|
||||
} else if self.need_boottime && ut.record_type() == utmpx::BOOT_TIME {
|
||||
self.print_boottime(&ut);
|
||||
|
@ -510,7 +522,7 @@ impl Who {
|
|||
if self.include_exit {
|
||||
buf.push_str(&format!(" {:<12}", exit));
|
||||
}
|
||||
println!("{}", buf.trim_right());
|
||||
println!("{}", buf.trim_end());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -11,7 +11,7 @@ path = "yes.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = "2.32"
|
||||
uucore = { path = "../uucore" }
|
||||
uucore = { path = "../uucore", features = ["zero-copy"] }
|
||||
|
||||
[features]
|
||||
latency = []
|
||||
|
|
|
@ -17,6 +17,7 @@ extern crate clap;
|
|||
extern crate uucore;
|
||||
|
||||
use clap::Arg;
|
||||
use uucore::zero_copy::ZeroCopyWriter;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{self, Write};
|
||||
|
||||
|
@ -83,9 +84,10 @@ fn prepare_buffer<'a>(input: &'a str, _buffer: &'a mut [u8; BUF_SIZE]) -> &'a [u
|
|||
}
|
||||
|
||||
pub fn exec(bytes: &[u8]) {
|
||||
let stdout_raw = io::stdout();
|
||||
let mut stdout = stdout_raw.lock();
|
||||
let mut stdin_raw = io::stdout();
|
||||
let mut writer = ZeroCopyWriter::with_default(&mut stdin_raw, |stdin| stdin.lock());
|
||||
loop {
|
||||
stdout.write_all(bytes).unwrap();
|
||||
// TODO: needs to check if pipe fails
|
||||
writer.write_all(bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
16
tests/common/util.rs
Executable file → Normal file
16
tests/common/util.rs
Executable file → Normal file
|
@ -110,8 +110,8 @@ impl CmdResult {
|
|||
/// stderr_only is a better choice unless stdout may or will be non-empty
|
||||
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> Box<&CmdResult> {
|
||||
assert_eq!(
|
||||
String::from(msg.as_ref()).trim_right(),
|
||||
self.stderr.trim_right()
|
||||
String::from(msg.as_ref()).trim_end(),
|
||||
self.stderr.trim_end()
|
||||
);
|
||||
Box::new(self)
|
||||
}
|
||||
|
@ -162,16 +162,16 @@ pub fn log_info<T: AsRef<str>, U: AsRef<str>>(msg: T, par: U) {
|
|||
}
|
||||
|
||||
pub fn recursive_copy(src: &Path, dest: &Path) -> Result<()> {
|
||||
if try!(fs::metadata(src)).is_dir() {
|
||||
if fs::metadata(src)?.is_dir() {
|
||||
for entry in try!(fs::read_dir(src)) {
|
||||
let entry = try!(entry);
|
||||
let entry = entry?;
|
||||
let mut new_dest = PathBuf::from(dest);
|
||||
new_dest.push(entry.file_name());
|
||||
if try!(fs::metadata(entry.path())).is_dir() {
|
||||
try!(fs::create_dir(&new_dest));
|
||||
try!(recursive_copy(&entry.path(), &new_dest));
|
||||
if fs::metadata(entry.path())?.is_dir() {
|
||||
fs::create_dir(&new_dest)?;
|
||||
recursive_copy(&entry.path(), &new_dest)?;
|
||||
} else {
|
||||
try!(fs::copy(&entry.path(), new_dest));
|
||||
fs::copy(&entry.path(), new_dest)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ mod test_passgrp {
|
|||
|
||||
#[test]
|
||||
fn test_grp2gid() {
|
||||
if cfg!(target_os = "macos") {
|
||||
assert_eq!(0, grp2gid("wheel").unwrap());
|
||||
if cfg!(target_os = "linux") || cfg!(target_os = "android") || cfg!(target_os = "windows") {
|
||||
assert_eq!(0, grp2gid("root").unwrap())
|
||||
} else {
|
||||
assert_eq!(0, grp2gid("root").unwrap());
|
||||
assert_eq!(0, grp2gid("wheel").unwrap());
|
||||
}
|
||||
assert!(grp2gid("88888888").is_err());
|
||||
assert!(grp2gid("agroupthatdoesntexist").is_err());
|
||||
|
@ -34,10 +34,10 @@ mod test_passgrp {
|
|||
|
||||
#[test]
|
||||
fn test_gid2grp() {
|
||||
if cfg!(target_os = "macos") {
|
||||
assert_eq!("wheel", gid2grp(0).unwrap());
|
||||
} else {
|
||||
if cfg!(target_os = "linux") || cfg!(target_os = "android") || cfg!(target_os = "windows") {
|
||||
assert_eq!("root", gid2grp(0).unwrap());
|
||||
} else {
|
||||
assert_eq!("wheel", gid2grp(0).unwrap());
|
||||
}
|
||||
assert!(gid2grp(88888888).is_err());
|
||||
}
|
||||
|
|
18
util/rewrite_rules.rs
Normal file
18
util/rewrite_rules.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
//! Rules to update the codebase using Rerast
|
||||
|
||||
/// Converts try!() to ?
|
||||
fn try_to_question_mark<T, E, X: From<E>>(r: Result<T, E>) -> Result<T, X> {
|
||||
replace!(try!(r) => r?);
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn trim_left_to_start(s: &str) {
|
||||
replace!(s.trim_left() => s.trim_start());
|
||||
replace!(s.trim_right() => s.trim_end());
|
||||
}
|
||||
|
||||
fn trim_left_matches_to_start<P: FnMut(char) -> bool>(s: &str, inner: P) {
|
||||
replace!(s.trim_left_matches(inner) => s.trim_start_matches(inner));
|
||||
replace!(s.trim_right_matches(inner) => s.trim_end_matches(inner));
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue