mirror of
https://github.com/levogevo/ffmpeg-builder.git
synced 2026-01-15 19:06:17 +00:00
Compare commits
8 Commits
7ce42985e2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 38c160e2bd | |||
| 47e287ef7f | |||
| 691d0f857a | |||
| 3c3fc6164c | |||
| 1adcaa15a4 | |||
| 108561a002 | |||
| ff1b0c2304 | |||
| ff656d477f |
1
Jenkinsfile
vendored
1
Jenkinsfile
vendored
@@ -15,7 +15,6 @@ pipeline {
|
||||
agent none
|
||||
environment {
|
||||
DEBUG = "1"
|
||||
HEADLESS = "1"
|
||||
}
|
||||
options { buildDiscarder logRotator(numToKeepStr: '4') }
|
||||
stages {
|
||||
|
||||
@@ -32,10 +32,13 @@ The default enabled libraries included in the `ffmpeg` build are:
|
||||
- libx264
|
||||
- libx265
|
||||
- libwebp
|
||||
- libvpx
|
||||
- libass
|
||||
- libvorbis
|
||||
- libmp3lame
|
||||
|
||||
The user-overridable compile options are:
|
||||
- `ENABLE`: configure what ffmpeg enables (default: libsvtav1_psy libopus libdav1d libaom librav1e libvmaf libx264 libx265 libwebp libmp3lame)
|
||||
- `ENABLE`: configure what ffmpeg enables (default: libsvtav1_psy libopus libdav1d libaom librav1e libvmaf libx264 libx265 libwebp libvpx libass libvorbis libmp3lame)
|
||||
- `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local)
|
||||
- `STATIC`: static or shared build (default: ON)
|
||||
- `LTO`: enable link time optimization (default: ON)
|
||||
@@ -78,7 +81,7 @@ encode -i input [options] output
|
||||
[-v] print relevant version info
|
||||
[-s] use same container as input, default is convert to mkv
|
||||
|
||||
[output] if unset, defaults to ${HOME}/av1-input-file-name.mkv
|
||||
[output] if unset, defaults to ${PWD}/av1-input-file-name.mkv
|
||||
|
||||
[-u] update script (git pull ffmpeg-builder)
|
||||
[-I] system install at /usr/local/bin/encode
|
||||
@@ -107,6 +110,7 @@ Example usage:
|
||||
## Estimate film-grain
|
||||
```bash
|
||||
efg -i input [options]
|
||||
[-P NUM] set preset (default: 10)
|
||||
[-l NUM] low value (default: 0)
|
||||
[-s NUM] step value (default: 1)
|
||||
[-h NUM] high value (default: 30)
|
||||
|
||||
419
lib/0-utils.sh
Normal file
419
lib/0-utils.sh
Normal file
@@ -0,0 +1,419 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
# ANSI colors
|
||||
RED='\e[0;31m'
|
||||
CYAN='\e[0;36m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
NC='\e[0m'
|
||||
|
||||
# echo wrappers
|
||||
echo_wrapper() {
|
||||
local args
|
||||
if [[ $1 == '-n' ]]; then
|
||||
args=("$1")
|
||||
shift
|
||||
fi
|
||||
# COLOR is override for using ${color}
|
||||
# shellcheck disable=SC2153
|
||||
if [[ ${COLOR} == 'OFF' ]]; then
|
||||
color=''
|
||||
endColor=''
|
||||
else
|
||||
endColor="${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${args[@]}" "${color}${word:-''}${endColor}" "$@"
|
||||
}
|
||||
echo_fail() { color="${RED}" word="FAIL" echo_wrapper "$@"; }
|
||||
echo_info() { color="${CYAN}" word="INFO" echo_wrapper "$@"; }
|
||||
echo_pass() { color="${GREEN}" word="PASS" echo_wrapper "$@"; }
|
||||
echo_warn() { color="${YELLOW}" word="WARN" echo_wrapper "$@"; }
|
||||
echo_exit() {
|
||||
echo_fail "$@"
|
||||
exit 1
|
||||
}
|
||||
void() { echo "$@" >/dev/null; }
|
||||
|
||||
echo_if_fail() {
|
||||
local cmd=("$@")
|
||||
local logName="${LOGNAME:-${RANDOM}}-"
|
||||
local out="${TMP_DIR}/${logName}stdout"
|
||||
local err="${TMP_DIR}/${logName}stderr"
|
||||
|
||||
# set trace to the cmdEvalTrace and open file descriptor
|
||||
local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace"
|
||||
exec 5>"${cmdEvalTrace}"
|
||||
export BASH_XTRACEFD=5
|
||||
|
||||
set -x
|
||||
"${cmd[@]}" >"${out}" 2>"${err}"
|
||||
local retval=$?
|
||||
|
||||
# unset and close file descriptor
|
||||
set +x
|
||||
exec 5>&-
|
||||
|
||||
# parse out relevant part of the trace
|
||||
local cmdEvalLines=()
|
||||
while IFS= read -r line; do
|
||||
line="${line/${PS4}/}"
|
||||
test "${line}" == 'set +x' && continue
|
||||
test "${line}" == '' && continue
|
||||
cmdEvalLines+=("${line}")
|
||||
done <"${cmdEvalTrace}"
|
||||
|
||||
if ! test ${retval} -eq 0; then
|
||||
echo
|
||||
echo_fail "command failed with ${retval}:"
|
||||
printf "%s\n" "${cmdEvalLines[@]}"
|
||||
echo_warn "command stdout:"
|
||||
tail -n 32 "${out}"
|
||||
echo_warn "command stderr:"
|
||||
tail -n 32 "${err}"
|
||||
echo
|
||||
fi
|
||||
if [[ -z ${LOGNAME} ]]; then
|
||||
rm "${out}" "${err}" "${cmdEvalTrace}"
|
||||
fi
|
||||
return ${retval}
|
||||
}
|
||||
|
||||
is_root_owned() {
|
||||
local path=$1
|
||||
local uid
|
||||
|
||||
if stat --version >/dev/null 2>&1; then
|
||||
# GNU coreutils (Linux)
|
||||
uid=$(stat -c '%u' "$path")
|
||||
else
|
||||
# BSD/macOS
|
||||
uid=$(stat -f '%u' "$path")
|
||||
fi
|
||||
|
||||
test "$uid" -eq 0
|
||||
}
|
||||
|
||||
dump_arr() {
|
||||
local arrayNames=("$@")
|
||||
for arrayName in "${arrayNames[@]}"; do
|
||||
declare -n array="${arrayName}"
|
||||
arrayExpanded=("${array[@]}")
|
||||
|
||||
# skip showing single element arrays by default
|
||||
if [[ ! ${#arrayExpanded[@]} -gt 1 ]]; then
|
||||
if [[ ${SHOW_SINGLE} == true ]]; then
|
||||
echo_info "${arrayName}='${arrayExpanded[*]}'"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
# don't care that the variable has "ARR"
|
||||
echo_info "${arrayName//"_ARR"/}"
|
||||
printf "\t%s\n" "${arrayExpanded[@]}"
|
||||
done
|
||||
}
|
||||
|
||||
has_cmd() {
|
||||
local cmds=("$@")
|
||||
local rv=0
|
||||
for cmd in "${cmds[@]}"; do
|
||||
command -v "${cmd}" >/dev/null 2>&1 || rv=1
|
||||
done
|
||||
|
||||
return ${rv}
|
||||
}
|
||||
|
||||
missing_cmd() {
|
||||
local cmds=("$@")
|
||||
local rv=1
|
||||
for cmd in "${cmds[@]}"; do
|
||||
if ! has_cmd "${cmd}"; then
|
||||
echo_warn "missing ${cmd}"
|
||||
rv=0
|
||||
fi
|
||||
done
|
||||
|
||||
return ${rv}
|
||||
}
|
||||
|
||||
bash_dirname() {
|
||||
local tmp=${1:-.}
|
||||
|
||||
[[ $tmp != *[!/]* ]] && {
|
||||
printf '/\n'
|
||||
return
|
||||
}
|
||||
|
||||
tmp=${tmp%%"${tmp##*[!/]}"}
|
||||
|
||||
[[ $tmp != */* ]] && {
|
||||
printf '.\n'
|
||||
return
|
||||
}
|
||||
|
||||
tmp=${tmp%/*}
|
||||
tmp=${tmp%%"${tmp##*[!/]}"}
|
||||
|
||||
printf '%s\n' "${tmp:-/}"
|
||||
}
|
||||
|
||||
bash_basename() {
|
||||
local tmp
|
||||
path="$1"
|
||||
suffix="${2:-''}"
|
||||
|
||||
tmp=${path%"${path##*[!/]}"}
|
||||
tmp=${tmp##*/}
|
||||
tmp=${tmp%"${suffix/"$tmp"/}"}
|
||||
|
||||
printf '%s\n' "${tmp:-/}"
|
||||
}
|
||||
|
||||
bash_realpath() {
|
||||
local file=$1
|
||||
local dir
|
||||
|
||||
# If the file is already absolute
|
||||
[[ $file == /* ]] && {
|
||||
printf '%s\n' "$file"
|
||||
return
|
||||
}
|
||||
|
||||
# Otherwise: split into directory + basename
|
||||
dir="$(bash_dirname "${file}")"
|
||||
file="$(bash_basename "${file}")"
|
||||
|
||||
# If no directory component, use current directory
|
||||
if [[ $dir == "$file" ]]; then
|
||||
dir="$PWD"
|
||||
else
|
||||
# Save current dir, move into target dir, capture $PWD, then return
|
||||
local oldpwd="$PWD"
|
||||
cd "$dir" || return 1
|
||||
dir="$PWD"
|
||||
cd "$oldpwd" || return 1
|
||||
fi
|
||||
|
||||
printf '%s/%s\n' "$dir" "$file"
|
||||
}
|
||||
|
||||
line_contains() {
|
||||
local line="$1"
|
||||
local substr="$2"
|
||||
if [[ $line == *"${substr}"* ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
line_starts_with() {
|
||||
local line="$1"
|
||||
local substr="$2"
|
||||
if [[ $line == "${substr}"* ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_linux() {
|
||||
line_contains "${OSTYPE}" 'linux'
|
||||
}
|
||||
|
||||
is_darwin() {
|
||||
line_contains "$(print_os)" darwin
|
||||
}
|
||||
|
||||
is_windows() {
|
||||
line_contains "$(print_os)" windows
|
||||
}
|
||||
|
||||
is_android() {
|
||||
line_contains "$(print_os)" android
|
||||
}
|
||||
|
||||
print_os() {
|
||||
# cached response
|
||||
if [[ -n ${FB_OS} ]]; then
|
||||
echo "${FB_OS}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
unset FB_OS
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
FB_OS="${ID}"
|
||||
if [[ ${VERSION_ID} != '' ]]; then
|
||||
FB_OS+="-${VERSION_ID}"
|
||||
fi
|
||||
if line_starts_with "${FB_OS}" 'arch'; then
|
||||
FB_OS='archlinux'
|
||||
fi
|
||||
else
|
||||
FB_OS="$(uname -o)"
|
||||
fi
|
||||
|
||||
# lowercase
|
||||
FB_OS="${FB_OS,,}"
|
||||
|
||||
# special treatment for windows
|
||||
if line_contains "${FB_OS}" 'windows' || line_contains "${FB_OS}" 'msys'; then
|
||||
FB_OS='windows'
|
||||
fi
|
||||
|
||||
echo "${FB_OS}"
|
||||
}
|
||||
|
||||
is_positive_integer() {
|
||||
local input="$1"
|
||||
if [[ ${input} != ?(-)+([[:digit:]]) || ${input} -lt 0 ]]; then
|
||||
echo_fail "${input} is not a positive integer"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
print_line_indent() {
|
||||
local line="$1"
|
||||
if [[ ${line} =~ ^( +) ]]; then
|
||||
echo -n "${BASH_REMATCH[1]}"
|
||||
fi
|
||||
}
|
||||
|
||||
replace_line() {
|
||||
local file="$1"
|
||||
local search="$2"
|
||||
local newLine="$3"
|
||||
local newFile="${TMP_DIR}/$(bash_basename "${file}")"
|
||||
|
||||
test -f "${newFile}" && rm "${newFile}"
|
||||
while IFS= read -r line; do
|
||||
if line_contains "${line}" "${search}"; then
|
||||
print_line_indent "${line}" >>"${newFile}"
|
||||
echo -en "${newLine}" >>"${newFile}"
|
||||
continue
|
||||
fi
|
||||
echo "${line}" >>"${newFile}"
|
||||
done <"${file}"
|
||||
|
||||
cp "${newFile}" "${file}"
|
||||
}
|
||||
|
||||
remove_line() {
|
||||
local file="$1"
|
||||
local search="$2"
|
||||
replace_line "${file}" "${search}" ''
|
||||
}
|
||||
|
||||
bash_sort() {
|
||||
local arr=("$@")
|
||||
local n=${#arr[@]}
|
||||
local i j val1 val2
|
||||
|
||||
# Bubble sort, numeric comparison
|
||||
for ((i = 0; i < n; i++)); do
|
||||
for ((j = 0; j < n - i - 1; j++)); do
|
||||
read -r val1 _ <<<"${arr[j]}"
|
||||
read -r val2 _ <<<"${arr[j + 1]}"
|
||||
if (("${val1}" > "${val2}")); then
|
||||
local tmp=${arr[j]}
|
||||
arr[j]=${arr[j + 1]}
|
||||
arr[j + 1]=$tmp
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
printf '%s\n' "${arr[@]}"
|
||||
}
|
||||
|
||||
_start_spinner() {
|
||||
local spinChars=(
|
||||
"-"
|
||||
'\'
|
||||
"|"
|
||||
"/"
|
||||
)
|
||||
|
||||
sleep 1
|
||||
|
||||
while true; do
|
||||
for ((ind = 0; ind < "${#spinChars[@]}"; ind++)); do
|
||||
echo -ne "${spinChars[${ind}]}" '\b\b'
|
||||
sleep .25
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
spinner() {
|
||||
local action="$1"
|
||||
local spinPidFile="${TMP_DIR}/.spinner-pid"
|
||||
case "${action}" in
|
||||
start)
|
||||
test -f "${spinPidFile}" && rm "${spinPidFile}"
|
||||
|
||||
_start_spinner &
|
||||
echo $! >"${spinPidFile}"
|
||||
;;
|
||||
stop)
|
||||
test -f "${spinPidFile}" && kill "$(<"${spinPidFile}")"
|
||||
echo -ne ' \n'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_pkgconfig_version() {
|
||||
local pkg="$1"
|
||||
pkg-config --modversion "${pkg}"
|
||||
}
|
||||
|
||||
using_cmake_4() {
|
||||
local cmakeVersion
|
||||
IFS=$' \t' read -r _ _ cmakeVersion <<<"$(command cmake --version)"
|
||||
line_starts_with "${cmakeVersion}" 4
|
||||
}
|
||||
|
||||
recreate_dir() {
|
||||
local dirs=("$@")
|
||||
for dir in "${dirs[@]}"; do
|
||||
test -d "${dir}" && rm -rf "${dir}"
|
||||
mkdir -p "${dir}" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
ensure_dir() {
|
||||
local dirs=("$@")
|
||||
for dir in "${dirs[@]}"; do
|
||||
test -d "${dir}" || mkdir -p "${dir}" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
get_remote_head() {
|
||||
local url="$1"
|
||||
local remoteHEAD=''
|
||||
IFS=$' \t' read -r remoteHEAD _ <<< \
|
||||
"$(git ls-remote "${url}" HEAD)"
|
||||
echo "${remoteHEAD}"
|
||||
}
|
||||
|
||||
fb_max() {
|
||||
local a="$1"
|
||||
local b="$2"
|
||||
test "${a}" -gt "${b}" &&
|
||||
echo "${a}" ||
|
||||
echo "${b}"
|
||||
}
|
||||
|
||||
print_padded() {
|
||||
local str="$1"
|
||||
local padding="$2"
|
||||
echo -n "${str}"
|
||||
for ((i = 0; i < padding - ${#str}; i++)); do
|
||||
echo -n ' '
|
||||
done
|
||||
}
|
||||
182
lib/build.sh
182
lib/build.sh
@@ -129,6 +129,19 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
|
||||
# cp "${compilerDir}/${genericT}" "${compilerDir}/${gnuT}" 2>/dev/null
|
||||
# cp "${compilerDir}/${genericT}" "${compilerDir}/${clangT}" 2>/dev/null
|
||||
done <<<"${compilerMap}"
|
||||
|
||||
# also add fake which command in case one does not exist
|
||||
# shellcheck disable=SC2016
|
||||
echo '#!/usr/bin/env bash
|
||||
which=""
|
||||
test -f /bin/which && which=/bin/which
|
||||
test -f /usr/bin/which && which=/usr/bin/which
|
||||
if [[ ${which} == "" ]]; then
|
||||
command -v "$@"
|
||||
else
|
||||
${which} "$@"
|
||||
fi' >"${compilerDir}/which"
|
||||
chmod +x "${compilerDir}/which"
|
||||
export PATH="${compilerDir}:${PATH}"
|
||||
fi
|
||||
|
||||
@@ -162,6 +175,11 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
|
||||
)
|
||||
PKG_CONFIG_PATH="${LIBDIR}/pkgconfig"
|
||||
|
||||
# cmake version 4 breaks some builds
|
||||
if using_cmake_4; then
|
||||
CMAKE_FLAGS+=("-DCMAKE_POLICY_VERSION_MINIMUM=3.5")
|
||||
fi
|
||||
|
||||
# add prefix include
|
||||
# TODO use cygpath for windows
|
||||
CPPFLAGS_ARR+=("-I${PREFIX}/include")
|
||||
@@ -238,8 +256,15 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
|
||||
"-DENABLE_SHARED=ON"
|
||||
"-DBUILD_SHARED_LIBS=ON"
|
||||
"-DCMAKE_INSTALL_RPATH=${LIBDIR}"
|
||||
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON"
|
||||
"-DCMAKE_EXE_LINKER_FLAGS=${LDFLAGS_ARR[*]}"
|
||||
)
|
||||
if is_darwin; then
|
||||
CMAKE_FLAGS+=(
|
||||
"-DCMAKE_MACOSX_RPATH=ON"
|
||||
"-DCMAKE_INSTALL_NAME_DIR=@rpath"
|
||||
)
|
||||
fi
|
||||
FFMPEG_EXTRA_FLAGS+=("--extra-ldflags=${LDFLAGS_ARR[*]}")
|
||||
LDFLAGS_ARR+=("-Wl,-rpath,${LIBDIR}")
|
||||
CONFIGURE_FLAGS+=(
|
||||
@@ -298,24 +323,21 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
|
||||
echo
|
||||
}
|
||||
|
||||
get_remote_head() {
|
||||
local url="$1"
|
||||
local remoteHEAD=''
|
||||
IFS=$' \t' read -r remoteHEAD _ <<< \
|
||||
"$(git ls-remote "${url}" HEAD)"
|
||||
echo "${remoteHEAD}"
|
||||
}
|
||||
|
||||
get_build_conf() {
|
||||
local getBuild="${1}"
|
||||
|
||||
local longestBuild=0
|
||||
local longestVer=0
|
||||
local longestExt=0
|
||||
local padding=4
|
||||
|
||||
# name version file-extension url dep1,dep2
|
||||
# shellcheck disable=SC2016
|
||||
local BUILDS_CONF='
|
||||
ffmpeg 8.0 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
|
||||
ffmpeg 8.0.1 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
|
||||
|
||||
libsvtav1_psy 3.0.2-B tar.gz https://github.com/BlueSwordM/svt-av1-psyex/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo
|
||||
hdr10plus_tool 1.7.1 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext}
|
||||
hdr10plus_tool 1.7.2 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext}
|
||||
dovi_tool 2.3.1 tar.gz https://github.com/quietvoid/dovi_tool/archive/refs/tags/${ver}.${ext}
|
||||
cpuinfo latest git https://github.com/pytorch/cpuinfo/
|
||||
|
||||
@@ -323,16 +345,18 @@ libsvtav1 3.1.2 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${v
|
||||
librav1e 0.8.1 tar.gz https://github.com/xiph/rav1e/archive/refs/tags/v${ver}.${ext}
|
||||
libaom 3.13.1 tar.gz https://storage.googleapis.com/aom-releases/libaom-${ver}.${ext}
|
||||
libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext}
|
||||
libopus 1.5.2 tar.gz https://github.com/xiph/opus/releases/download/v${ver}/opus-${ver}.${ext}
|
||||
libdav1d 1.5.1 tar.xz http://downloads.videolan.org/videolan/dav1d/${ver}/dav1d-${ver}.${ext}
|
||||
libopus 1.6 tar.gz https://github.com/xiph/opus/archive/refs/tags/v${ver}.${ext}
|
||||
libdav1d 1.5.3 tar.xz https://downloads.videolan.org/videolan/dav1d/${ver}/dav1d-${ver}.${ext}
|
||||
libx264 latest git https://code.videolan.org/videolan/x264.git
|
||||
libmp3lame 3.100 tar.gz https://pilotfiber.dl.sourceforge.net/project/lame/lame/${ver}/lame-${ver}.${ext}
|
||||
libvpx 1.15.2 tar.gz https://github.com/webmproject/libvpx/archive/refs/tags/v${ver}.${ext}
|
||||
libvorbis 1.3.7 tar.xz https://github.com/xiph/vorbis/releases/download/v1.3.7/libvorbis-${ver}.${ext}
|
||||
|
||||
libvorbis 1.3.7 tar.xz https://github.com/xiph/vorbis/releases/download/v${ver}/libvorbis-${ver}.${ext} libogg
|
||||
libogg 1.3.6 tar.xz https://github.com/xiph/ogg/releases/download/v${ver}/libogg-${ver}.${ext}
|
||||
|
||||
libwebp 1.6.0 tar.gz https://github.com/webmproject/libwebp/archive/refs/tags/v${ver}.${ext} libpng,libjpeg
|
||||
libjpeg 3.0.3 tar.gz https://github.com/winlibs/libjpeg/archive/refs/tags/libjpeg-turbo-${ver}.${ext}
|
||||
libpng 1.6.50 tar.gz https://github.com/pnggroup/libpng/archive/refs/tags/v${ver}.${ext} zlib
|
||||
libpng 1.6.53 tar.gz https://github.com/pnggroup/libpng/archive/refs/tags/v${ver}.${ext} zlib
|
||||
zlib 1.3.1 tar.gz https://github.com/madler/zlib/archive/refs/tags/v${ver}.${ext}
|
||||
|
||||
libplacebo 7.351.0 tar.gz https://github.com/haasn/libplacebo/archive/refs/tags/v${ver}.${ext} glslang,vulkan_loader,glad
|
||||
@@ -343,14 +367,25 @@ glad 2.0.8 tar.gz https://github.com/Dav1dde/glad/archive/refs/tags/v${ver}.
|
||||
|
||||
libx265 4.1 tar.gz https://bitbucket.org/multicoreware/x265_git/downloads/x265_${ver}.${ext} libnuma
|
||||
libnuma 2.0.19 tar.gz https://github.com/numactl/numactl/archive/refs/tags/v${ver}.${ext}
|
||||
'
|
||||
|
||||
libass 0.17.4 tar.xz https://github.com/libass/libass/releases/download/${ver}/libass-${ver}.${ext} freetype,fribidi,libunibreak
|
||||
freetype 2.14.1 tar.xz https://downloads.sourceforge.net/freetype/freetype-${ver}.${ext} libpng,harfbuzz
|
||||
harfbuzz 12.3.0 tar.xz https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.${ext}
|
||||
fribidi 1.0.16 tar.xz https://github.com/fribidi/fribidi/releases/download/v${ver}/fribidi-${ver}.${ext}
|
||||
libunibreak 6.1 tar.gz https://github.com/adah1972/libunibreak/releases/download/libunibreak_${ver//./_}/libunibreak-${ver}.${ext}
|
||||
'
|
||||
local supported_builds=()
|
||||
unset ver ext url deps extractedDir
|
||||
while read -r line; do
|
||||
test "${line}" == '' && continue
|
||||
IFS=$' \t' read -r build ver ext url deps <<<"${line}"
|
||||
supported_builds+=("${build}")
|
||||
|
||||
# padding support
|
||||
longestBuild="$(fb_max "${#build}" "${longestBuild}")"
|
||||
longestVer="$(fb_max "${#ver}" "${longestVer}")"
|
||||
longestExt="$(fb_max "${#ext}" "${longestExt}")"
|
||||
|
||||
if [[ ${getBuild} != "${build}" ]]; then
|
||||
build=''
|
||||
continue
|
||||
@@ -358,11 +393,27 @@ libnuma 2.0.19 tar.gz https://github.com/numactl/numactl/archive/refs/tags/v
|
||||
break
|
||||
done <<<"${BUILDS_CONF}"
|
||||
|
||||
# special arg to print supported builds only
|
||||
if [[ ${getBuild} == 'supported' ]]; then
|
||||
echo "${supported_builds[@]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# special arg to print BUILDS_CONF but formatted with spaces
|
||||
if [[ ${getBuild} == 'format-builds-conf' ]]; then
|
||||
echo "local BUILDS_CONF='"
|
||||
while read -r line; do
|
||||
IFS=$' \t' read -r build ver ext url deps <<<"${line}"
|
||||
print_padded "${build}" $((padding + longestBuild))
|
||||
print_padded "${ver}" $((padding + longestVer))
|
||||
print_padded "${ext}" $((padding + longestExt))
|
||||
print_padded "${url}" "${padding}"
|
||||
echo " ${deps}"
|
||||
done <<<"${BUILDS_CONF}"
|
||||
echo "'"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ${build} == '' ]]; then
|
||||
echo_fail "build ${getBuild} is not supported"
|
||||
return 1
|
||||
@@ -406,7 +457,7 @@ download_release() {
|
||||
continue
|
||||
fi
|
||||
test -d "${alreadyBuilt}" || continue
|
||||
echo_warn "removing wrong version: ${extractedDir}"
|
||||
echo_warn "removing wrong version: ${alreadyBuilt}"
|
||||
rm -rf "${alreadyBuilt}"
|
||||
done
|
||||
|
||||
@@ -608,10 +659,21 @@ sanitize_sysroot_libs() {
|
||||
|
||||
for lib in "${libs[@]}"; do
|
||||
local libPath="${LIBDIR}/${lib}"
|
||||
local useLib="${libPath}.${USE_LIB_SUFF}"
|
||||
local foundLib=false
|
||||
|
||||
if [[ ! -f ${useLib} ]]; then
|
||||
echo_fail "could not find ${useLib}, something is wrong"
|
||||
for useLib in "${libPath}"*"${USE_LIB_SUFF}"; do
|
||||
test -f "${useLib}" || continue
|
||||
foundLib=true
|
||||
# darwin sometimes fails to set rpath correctly
|
||||
if is_darwin && [[ ${STATIC} == 'OFF' ]]; then
|
||||
install_name_tool \
|
||||
-id "${useLib}" \
|
||||
"${useLib}" || return 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${foundLib} == false ]]; then
|
||||
echo_fail "could not find ${libPath}*${USE_LIB_SUFF}, something is wrong"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -762,6 +824,11 @@ build_libvorbis() {
|
||||
libvorbis libvorbisenc libvorbisfile || return 1
|
||||
}
|
||||
|
||||
build_libogg() {
|
||||
meta_cmake_build || return 1
|
||||
sanitize_sysroot_libs libogg || return 1
|
||||
}
|
||||
|
||||
build_libwebp() {
|
||||
if is_android; then
|
||||
replace_line CMakeLists.txt \
|
||||
@@ -812,19 +879,14 @@ build_spirv_headers() {
|
||||
|
||||
build_libx265() {
|
||||
# libx265 does not support cmake >= 4
|
||||
local cmakeVersion verMajor
|
||||
IFS=$' \t' read -r _ _ cmakeVersion <<<"$(cmake --version)"
|
||||
IFS='.' read -r verMajor _ _ <<<"${cmakeVersion}"
|
||||
local policyFlag=''
|
||||
if [[ ! ${verMajor} -lt 4 ]]; then
|
||||
if using_cmake_4; then
|
||||
remove_line "source/CMakeLists.txt" "cmake_policy(SET CMP0025 OLD)" || return 1
|
||||
remove_line "source/CMakeLists.txt" "cmake_policy(SET CMP0054 OLD)" || return 1
|
||||
policyFlag="-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
|
||||
fi
|
||||
|
||||
meta_cmake_build \
|
||||
-DHIGH_BIT_DEPTH=ON \
|
||||
-DENABLE_HDR10_PLUS=OFF ${policyFlag} \
|
||||
-DENABLE_HDR10_PLUS=OFF \
|
||||
-S source || return 1
|
||||
sanitize_sysroot_libs libx265 || return 1
|
||||
del_pkgconfig_gcc_s x265.pc || return 1
|
||||
@@ -859,8 +921,8 @@ build_libplacebo() {
|
||||
# copy downloaded glad release as "submodule"
|
||||
(
|
||||
installDir="${PWD}/3rdparty/glad"
|
||||
get_build_conf glad
|
||||
CLEAN=OFF download_release
|
||||
get_build_conf glad || exit 1
|
||||
CLEAN=OFF download_release || exit 1
|
||||
cd "${extractedDir}" || exit 1
|
||||
cp -r ./* "${installDir}"
|
||||
) || return 1
|
||||
@@ -902,6 +964,26 @@ build_libvmaf() {
|
||||
fi
|
||||
}
|
||||
|
||||
build_freetype() {
|
||||
meta_meson_build \
|
||||
-D tests=disabled || return 1
|
||||
sanitize_sysroot_libs libfreetype || return 1
|
||||
}
|
||||
|
||||
build_harfbuzz() {
|
||||
meta_meson_build \
|
||||
-D tests=disabled \
|
||||
-D docs=disabled \
|
||||
-D doc_tests=false || return 1
|
||||
sanitize_sysroot_libs libharfbuzz || return 1
|
||||
}
|
||||
|
||||
build_fribidi() {
|
||||
meta_meson_build \
|
||||
-D tests=false || return 1
|
||||
sanitize_sysroot_libs libfribidi || return 1
|
||||
}
|
||||
|
||||
### PYTHON ###
|
||||
build_glad() {
|
||||
true
|
||||
@@ -957,7 +1039,7 @@ build_libvpx() {
|
||||
--enable-vp8 \
|
||||
--enable-vp9 \
|
||||
--enable-vp9-highbitdepth \
|
||||
--enable-better-hw-compatability \
|
||||
--enable-better-hw-compatibility \
|
||||
--enable-webm-io \
|
||||
--enable-libyuv || return 1
|
||||
sanitize_sysroot_libs libvpx || return 1
|
||||
@@ -990,6 +1072,16 @@ build_libnuma() {
|
||||
sanitize_sysroot_libs libnuma || return 1
|
||||
}
|
||||
|
||||
build_libunibreak() {
|
||||
meta_configure_build || return 1
|
||||
sanitize_sysroot_libs libunibreak || return 1
|
||||
}
|
||||
|
||||
build_libass() {
|
||||
meta_configure_build || return 1
|
||||
sanitize_sysroot_libs libass || return 1
|
||||
}
|
||||
|
||||
add_project_versioning_to_ffmpeg() {
|
||||
# embed this project's enables/versions
|
||||
# into ffmpeg with FFMPEG_BUILDER_INFO
|
||||
@@ -1012,34 +1104,10 @@ add_project_versioning_to_ffmpeg() {
|
||||
echo_fail "could not find ${fname} to add project versioning"
|
||||
fi
|
||||
|
||||
local searchFor='static void print_all_libs_info'
|
||||
local foundUsageStart=0
|
||||
local newOptFile="${TMP_DIR}/${fname}"
|
||||
test -f "${newOptFile}" && rm "${newOptFile}"
|
||||
while read -r line; do
|
||||
# if we found the line previously, add the versioning
|
||||
if [[ ${foundUsageStart} -eq 1 ]]; then
|
||||
if line_starts_with "${line}" '}'; then
|
||||
echo_info "found ${line} on ${lineNum}"
|
||||
for info in "${FFMPEG_BUILDER_INFO[@]}"; do
|
||||
local newline="av_log(NULL, AV_LOG_INFO, \"${info}\n\");"
|
||||
echo "${newline}" >>"${newOptFile}"
|
||||
lineNum=$((lineNum + 1))
|
||||
done
|
||||
newline="av_log(NULL, AV_LOG_INFO, \"\n\");"
|
||||
echo "${newline}" >>"${newOptFile}"
|
||||
foundUsageStart=0
|
||||
fi
|
||||
fi
|
||||
# find the line we are searching for
|
||||
if line_contains "${line}" "${searchFor}"; then
|
||||
foundUsageStart=1
|
||||
fi
|
||||
# start building the new file
|
||||
echo "${line}" >>"${newOptFile}"
|
||||
done <"${optFile}"
|
||||
|
||||
cp "${newOptFile}" "${optFile}" || return 1
|
||||
local printLibLine='print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);'
|
||||
local newPrintLibLine="${printLibLine} "
|
||||
newPrintLibLine+="$(printf 'av_log(NULL, AV_LOG_INFO, "%s\\\\n"); ' "${FFMPEG_BUILDER_INFO[@]}")"
|
||||
replace_line "${optFile}" "${printLibLine}" "${newPrintLibLine}" || return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ libx264 \
|
||||
libx265 \
|
||||
libwebp \
|
||||
libvpx \
|
||||
libass \
|
||||
libvorbis \
|
||||
libmp3lame\
|
||||
"
|
||||
|
||||
@@ -19,7 +19,7 @@ set_docker_run_flags() {
|
||||
-v "${REPO_DIR}:${REPO_DIR}"
|
||||
-w "${REPO_DIR}"
|
||||
-e "DEBUG=${DEBUG}"
|
||||
-e "HEADLESS=${HEADLESS}"
|
||||
-t
|
||||
)
|
||||
for opt in "${FB_COMP_OPTS[@]}"; do
|
||||
declare -n defOptVal="DEFAULT_${opt}"
|
||||
|
||||
29
lib/efg.sh
29
lib/efg.sh
@@ -2,6 +2,7 @@
|
||||
|
||||
efg_usage() {
|
||||
echo "efg -i input [options]"
|
||||
echo -e "\t[-P NUM] set preset (default: ${PRESET})"
|
||||
echo -e "\t[-l NUM] low value (default: ${LOW})"
|
||||
echo -e "\t[-s NUM] step value (default: ${STEP})"
|
||||
echo -e "\t[-h NUM] high value (default: ${HIGH})"
|
||||
@@ -12,10 +13,11 @@ efg_usage() {
|
||||
}
|
||||
|
||||
set_efg_opts() {
|
||||
local opts='pl:s:h:i:IU'
|
||||
local opts='P:pl:s:h:i:IU'
|
||||
local numOpts=${#opts}
|
||||
# default values
|
||||
unset INPUT
|
||||
PRESET=10
|
||||
LOW=0
|
||||
STEP=1
|
||||
HIGH=30
|
||||
@@ -30,6 +32,13 @@ set_efg_opts() {
|
||||
local OPTARG OPTIND
|
||||
while getopts "${opts}" flag; do
|
||||
case "${flag}" in
|
||||
P)
|
||||
if ! is_positive_integer "${OPTARG}"; then
|
||||
efg_usage
|
||||
return 1
|
||||
fi
|
||||
PRESET="${OPTARG}"
|
||||
;;
|
||||
I)
|
||||
echo_warn "attempting install"
|
||||
sudo ln -sf "${SCRIPT_DIR}/efg.sh" \
|
||||
@@ -169,20 +178,26 @@ efg_segment() {
|
||||
}
|
||||
|
||||
efg_encode() {
|
||||
echo -n >"${GRAIN_LOG}"
|
||||
local grainLogWIP="${GRAIN_LOG}.wip"
|
||||
echo -n >"${grainLogWIP}"
|
||||
for vid in "${EFG_DIR}/"*.mkv; do
|
||||
echo "file: ${vid}" >>"${GRAIN_LOG}"
|
||||
echo "file: ${vid}" >>"${grainLogWIP}"
|
||||
for ((grain = LOW; grain <= HIGH; grain += STEP)); do
|
||||
local file="$(bash_basename "${vid}")"
|
||||
local out="${EFG_DIR}/grain-${grain}-${file}"
|
||||
echo_info "encoding ${file} with grain ${grain}"
|
||||
echo_if_fail encode -P 10 -g ${grain} -i "${vid}" "${out}"
|
||||
echo -e "\tgrain: ${grain}, bitrate: $(get_avg_bitrate "${out}")" >>"${GRAIN_LOG}"
|
||||
rm "${out}"
|
||||
echo_if_fail encode -P "${PRESET}" -g ${grain} -i "${vid}" "${out}" || return 1
|
||||
echo -e "\tgrain: ${grain}, bitrate: $(get_avg_bitrate "${out}")" >>"${grainLogWIP}"
|
||||
rm "${out}" || return 1
|
||||
done
|
||||
# remove segment once complete
|
||||
rm "${vid}" || return 1
|
||||
done
|
||||
|
||||
less "${GRAIN_LOG}"
|
||||
# atomic move of grain log
|
||||
mv "${grainLogWIP}" "${GRAIN_LOG}" || return 1
|
||||
|
||||
echo "$(<"${GRAIN_LOG}")"
|
||||
}
|
||||
|
||||
efg_plot() {
|
||||
|
||||
@@ -154,7 +154,7 @@ encode_usage() {
|
||||
echo -e "\t[-d] enable dolby vision (default: ${DV_TOGGLE})"
|
||||
echo -e "\t[-v] print relevant version info"
|
||||
echo -e "\t[-s] use same container as input, default is convert to mkv"
|
||||
echo -e "\n\t[output] if unset, defaults to \${HOME}/av1-input-file-name.mkv"
|
||||
echo -e "\n\t[output] if unset, defaults to \${PWD}/av1-input-file-name.mkv"
|
||||
echo -e "\n\t[-u] update script (git pull ffmpeg-builder)"
|
||||
echo -e "\t[-I] system install at ${ENCODE_INSTALL_PATH}"
|
||||
echo -e "\t[-U] uninstall from ${ENCODE_INSTALL_PATH}"
|
||||
@@ -271,7 +271,7 @@ set_encode_opts() {
|
||||
OUTPUT="${*: -1}"
|
||||
else
|
||||
local basename="$(bash_basename "${INPUT}")"
|
||||
OUTPUT="${HOME}/av1-${basename}"
|
||||
OUTPUT="${PWD}/av1-${basename}"
|
||||
fi
|
||||
|
||||
# use same container for output
|
||||
@@ -339,11 +339,13 @@ gen_encode_script() {
|
||||
"spy-rd=1"
|
||||
"psy-rd=1"
|
||||
"sharpness=3"
|
||||
"enable-overlays=1"
|
||||
"enable-overlays=0"
|
||||
"hbd-mds=1"
|
||||
"scd=1"
|
||||
"fast-decode=1"
|
||||
"enable-variance-boost=1"
|
||||
"enable-qm=1"
|
||||
"chroma-qm-min-10"
|
||||
"qm-min=4"
|
||||
"qm-max=15"
|
||||
)
|
||||
@@ -447,7 +449,7 @@ gen_encode_script() {
|
||||
echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1'
|
||||
|
||||
# track-stats and clear title
|
||||
if [[ ${FILE_EXT} == 'mkv' ]]; then
|
||||
if [[ ${FILE_EXT} == 'mkv' ]] && has_cmd mkvpropedit; then
|
||||
{
|
||||
echo
|
||||
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags'
|
||||
|
||||
@@ -68,11 +68,13 @@ print_req_pkgs() {
|
||||
build-essential libssl-dev gobjc++
|
||||
mawk libc6-dev mediainfo ninja-build
|
||||
mkvtoolnix libgtest-dev lld
|
||||
libfontconfig-dev libglib2.0-dev
|
||||
)
|
||||
# shellcheck disable=SC2034
|
||||
local pacman_pkgs=(
|
||||
"${common_linux_pkgs[@]}" base-devel
|
||||
python-pipx ninja lld mkvtoolnix-cli
|
||||
glib2-devel
|
||||
)
|
||||
# shellcheck disable=SC2034
|
||||
local dnf_pkgs=(
|
||||
@@ -82,7 +84,7 @@ print_req_pkgs() {
|
||||
libstdc++-static libstdc++-devel
|
||||
llvm-cmake-utils llvm-devel
|
||||
llvm-static compiler-rt lld
|
||||
mkvtoolnix
|
||||
mkvtoolnix glib2-static
|
||||
)
|
||||
# shellcheck disable=SC2034
|
||||
local pkg_pkgs=(
|
||||
|
||||
383
lib/utils.sh
383
lib/utils.sh
@@ -1,383 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
# ANSI colors
|
||||
RED='\e[0;31m'
|
||||
CYAN='\e[0;36m'
|
||||
GREEN='\e[0;32m'
|
||||
YELLOW='\e[0;33m'
|
||||
NC='\e[0m'
|
||||
|
||||
# echo wrappers
|
||||
echo_wrapper() {
|
||||
local args
|
||||
if [[ $1 == '-n' ]]; then
|
||||
args=("$1")
|
||||
shift
|
||||
fi
|
||||
# COLOR is override for using ${color}
|
||||
# shellcheck disable=SC2153
|
||||
if [[ ${COLOR} == 'OFF' ]]; then
|
||||
color=''
|
||||
endColor=''
|
||||
else
|
||||
endColor="${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${args[@]}" "${color}${word:-''}${endColor}" "$@"
|
||||
}
|
||||
echo_fail() { color="${RED}" word="FAIL" echo_wrapper "$@"; }
|
||||
echo_info() { color="${CYAN}" word="INFO" echo_wrapper "$@"; }
|
||||
echo_pass() { color="${GREEN}" word="PASS" echo_wrapper "$@"; }
|
||||
echo_warn() { color="${YELLOW}" word="WARN" echo_wrapper "$@"; }
|
||||
echo_exit() {
|
||||
echo_fail "$@"
|
||||
exit 1
|
||||
}
|
||||
void() { echo "$@" >/dev/null; }
|
||||
|
||||
echo_if_fail() {
|
||||
local cmd=("$@")
|
||||
local logName="${LOGNAME:-${RANDOM}}-"
|
||||
local out="${TMP_DIR}/${logName}stdout"
|
||||
local err="${TMP_DIR}/${logName}stderr"
|
||||
|
||||
# set trace to the cmdEvalTrace and open file descriptor
|
||||
local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace"
|
||||
exec 5>"${cmdEvalTrace}"
|
||||
export BASH_XTRACEFD=5
|
||||
|
||||
set -x
|
||||
"${cmd[@]}" >"${out}" 2>"${err}"
|
||||
local retval=$?
|
||||
|
||||
# unset and close file descriptor
|
||||
set +x
|
||||
exec 5>&-
|
||||
|
||||
# parse out relevant part of the trace
|
||||
local cmdEvalLines=()
|
||||
while IFS= read -r line; do
|
||||
line="${line/${PS4}/}"
|
||||
test "${line}" == 'set +x' && continue
|
||||
test "${line}" == '' && continue
|
||||
cmdEvalLines+=("${line}")
|
||||
done <"${cmdEvalTrace}"
|
||||
|
||||
if ! test ${retval} -eq 0; then
|
||||
echo
|
||||
echo_fail "command failed with ${retval}:"
|
||||
printf "%s\n" "${cmdEvalLines[@]}"
|
||||
echo_warn "command stdout:"
|
||||
tail -n 32 "${out}"
|
||||
echo_warn "command stderr:"
|
||||
tail -n 32 "${err}"
|
||||
echo
|
||||
fi
|
||||
if [[ -z ${LOGNAME} ]]; then
|
||||
rm "${out}" "${err}" "${cmdEvalTrace}"
|
||||
fi
|
||||
return ${retval}
|
||||
}
|
||||
|
||||
is_root_owned() {
|
||||
local path=$1
|
||||
local uid
|
||||
|
||||
if stat --version >/dev/null 2>&1; then
|
||||
# GNU coreutils (Linux)
|
||||
uid=$(stat -c '%u' "$path")
|
||||
else
|
||||
# BSD/macOS
|
||||
uid=$(stat -f '%u' "$path")
|
||||
fi
|
||||
|
||||
test "$uid" -eq 0
|
||||
}
|
||||
|
||||
dump_arr() {
|
||||
local arrayNames=("$@")
|
||||
for arrayName in "${arrayNames[@]}"; do
|
||||
declare -n array="${arrayName}"
|
||||
arrayExpanded=("${array[@]}")
|
||||
|
||||
# skip showing single element arrays by default
|
||||
if [[ ! ${#arrayExpanded[@]} -gt 1 ]]; then
|
||||
if [[ ${SHOW_SINGLE} == true ]]; then
|
||||
echo_info "${arrayName}='${arrayExpanded[*]}'"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
# don't care that the variable has "ARR"
|
||||
echo_info "${arrayName//"_ARR"/}"
|
||||
printf "\t%s\n" "${arrayExpanded[@]}"
|
||||
done
|
||||
}
|
||||
|
||||
has_cmd() {
|
||||
local cmds=("$@")
|
||||
local rv=0
|
||||
for cmd in "${cmds[@]}"; do
|
||||
command -v "${cmd}" >/dev/null 2>&1 || rv=1
|
||||
done
|
||||
|
||||
return ${rv}
|
||||
}
|
||||
|
||||
missing_cmd() {
|
||||
local cmds=("$@")
|
||||
local rv=1
|
||||
for cmd in "${cmds[@]}"; do
|
||||
if ! has_cmd "${cmd}"; then
|
||||
echo_warn "missing ${cmd}"
|
||||
rv=0
|
||||
fi
|
||||
done
|
||||
|
||||
return ${rv}
|
||||
}
|
||||
|
||||
bash_dirname() {
|
||||
local tmp=${1:-.}
|
||||
|
||||
[[ $tmp != *[!/]* ]] && {
|
||||
printf '/\n'
|
||||
return
|
||||
}
|
||||
|
||||
tmp=${tmp%%"${tmp##*[!/]}"}
|
||||
|
||||
[[ $tmp != */* ]] && {
|
||||
printf '.\n'
|
||||
return
|
||||
}
|
||||
|
||||
tmp=${tmp%/*}
|
||||
tmp=${tmp%%"${tmp##*[!/]}"}
|
||||
|
||||
printf '%s\n' "${tmp:-/}"
|
||||
}
|
||||
|
||||
bash_basename() {
|
||||
local tmp
|
||||
path="$1"
|
||||
suffix="${2:-''}"
|
||||
|
||||
tmp=${path%"${path##*[!/]}"}
|
||||
tmp=${tmp##*/}
|
||||
tmp=${tmp%"${suffix/"$tmp"/}"}
|
||||
|
||||
printf '%s\n' "${tmp:-/}"
|
||||
}
|
||||
|
||||
bash_realpath() {
|
||||
local file=$1
|
||||
local dir
|
||||
|
||||
# If the file is already absolute
|
||||
[[ $file == /* ]] && {
|
||||
printf '%s\n' "$file"
|
||||
return
|
||||
}
|
||||
|
||||
# Otherwise: split into directory + basename
|
||||
dir="$(bash_dirname "${file}")"
|
||||
file="$(bash_basename "${file}")"
|
||||
|
||||
# If no directory component, use current directory
|
||||
if [[ $dir == "$file" ]]; then
|
||||
dir="$PWD"
|
||||
else
|
||||
# Save current dir, move into target dir, capture $PWD, then return
|
||||
local oldpwd="$PWD"
|
||||
cd "$dir" || return 1
|
||||
dir="$PWD"
|
||||
cd "$oldpwd" || return 1
|
||||
fi
|
||||
|
||||
printf '%s/%s\n' "$dir" "$file"
|
||||
}
|
||||
|
||||
line_contains() {
|
||||
local line="$1"
|
||||
local substr="$2"
|
||||
if [[ $line == *"${substr}"* ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
line_starts_with() {
|
||||
local line="$1"
|
||||
local substr="$2"
|
||||
if [[ $line == "${substr}"* ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_linux() {
|
||||
line_contains "${OSTYPE}" 'linux'
|
||||
}
|
||||
|
||||
is_darwin() {
|
||||
line_contains "$(print_os)" darwin
|
||||
}
|
||||
|
||||
is_windows() {
|
||||
line_contains "$(print_os)" windows
|
||||
}
|
||||
|
||||
is_android() {
|
||||
line_contains "$(print_os)" android
|
||||
}
|
||||
|
||||
print_os() {
|
||||
# cached response
|
||||
if [[ -n ${FB_OS} ]]; then
|
||||
echo "${FB_OS}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
unset FB_OS
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
FB_OS="${ID}"
|
||||
if [[ ${VERSION_ID} != '' ]]; then
|
||||
FB_OS+="-${VERSION_ID}"
|
||||
fi
|
||||
if line_starts_with "${FB_OS}" 'arch'; then
|
||||
FB_OS='archlinux'
|
||||
fi
|
||||
else
|
||||
FB_OS="$(uname -o)"
|
||||
fi
|
||||
|
||||
# lowercase
|
||||
FB_OS="${FB_OS,,}"
|
||||
|
||||
# special treatment for windows
|
||||
if line_contains "${FB_OS}" 'windows' || line_contains "${FB_OS}" 'msys'; then
|
||||
FB_OS='windows'
|
||||
fi
|
||||
|
||||
echo "${FB_OS}"
|
||||
}
|
||||
|
||||
is_positive_integer() {
|
||||
local input="$1"
|
||||
if [[ ${input} != ?(-)+([[:digit:]]) || ${input} -lt 0 ]]; then
|
||||
echo_fail "${input} is not a positive integer"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
replace_line() {
|
||||
local file="$1"
|
||||
local search="$2"
|
||||
local newLine="$3"
|
||||
local newFile="${TMP_DIR}/$(bash_basename "${file}")"
|
||||
|
||||
test -f "${newFile}" && rm "${newFile}"
|
||||
while read -r line; do
|
||||
if line_contains "${line}" "${search}"; then
|
||||
echo -en "${newLine}" >>"${newFile}"
|
||||
continue
|
||||
fi
|
||||
echo "${line}" >>"${newFile}"
|
||||
done <"${file}"
|
||||
|
||||
cp "${newFile}" "${file}"
|
||||
}
|
||||
|
||||
remove_line() {
|
||||
local file="$1"
|
||||
local search="$2"
|
||||
replace_line "${file}" "${search}" ''
|
||||
}
|
||||
|
||||
bash_sort() {
|
||||
local arr=("$@")
|
||||
local n=${#arr[@]}
|
||||
local i j val1 val2
|
||||
|
||||
# Bubble sort, numeric comparison
|
||||
for ((i = 0; i < n; i++)); do
|
||||
for ((j = 0; j < n - i - 1; j++)); do
|
||||
read -r val1 _ <<<"${arr[j]}"
|
||||
read -r val2 _ <<<"${arr[j + 1]}"
|
||||
if (("${val1}" > "${val2}")); then
|
||||
local tmp=${arr[j]}
|
||||
arr[j]=${arr[j + 1]}
|
||||
arr[j + 1]=$tmp
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
printf '%s\n' "${arr[@]}"
|
||||
}
|
||||
|
||||
_start_spinner() {
|
||||
local spinChars=(
|
||||
"-"
|
||||
'\'
|
||||
"|"
|
||||
"/"
|
||||
)
|
||||
|
||||
sleep 1
|
||||
|
||||
while true; do
|
||||
for ((ind = 0; ind < "${#spinChars[@]}"; ind++)); do
|
||||
echo -ne "${spinChars[${ind}]}" '\b\b'
|
||||
sleep .25
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
spinner() {
|
||||
local action="$1"
|
||||
local spinPidFile="${TMP_DIR}/.spinner-pid"
|
||||
case "${action}" in
|
||||
start)
|
||||
test -f "${spinPidFile}" && rm "${spinPidFile}"
|
||||
|
||||
# don't want to clutter logs if running headless
|
||||
test "${HEADLESS}" == '1' && return
|
||||
|
||||
_start_spinner &
|
||||
echo $! >"${spinPidFile}"
|
||||
;;
|
||||
stop)
|
||||
test -f "${spinPidFile}" && kill "$(<"${spinPidFile}")"
|
||||
echo -ne ' \n'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_pkgconfig_version() {
|
||||
local pkg="$1"
|
||||
pkg-config --modversion "${pkg}"
|
||||
}
|
||||
|
||||
recreate_dir() {
|
||||
local dirs=("$@")
|
||||
for dir in "${dirs[@]}"; do
|
||||
test -d "${dir}" && rm -rf "${dir}"
|
||||
mkdir -p "${dir}" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
ensure_dir() {
|
||||
local dirs=("$@")
|
||||
for dir in "${dirs[@]}"; do
|
||||
test -d "${dir}" || mkdir -p "${dir}" || return 1
|
||||
done
|
||||
}
|
||||
@@ -6,10 +6,10 @@ inotifywait -m -r \
|
||||
-e close_write \
|
||||
-e moved_to \
|
||||
--format '%w%f' \
|
||||
"$base/lib" \
|
||||
"$base/scripts" \
|
||||
"$base/main.sh" | while read -r file; do
|
||||
"${base}/lib" \
|
||||
"${base}/scripts" \
|
||||
"${base}/main.sh" | while read -r file; do
|
||||
if [[ -f $file && $file =~ .sh ]]; then
|
||||
shfmt --write --simplify "$file"
|
||||
shfmt --indent 4 --write --simplify "${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user