Files
just-nixpkgs/justfile
2025-11-04 12:52:24 +01:00

1605 lines
70 KiB
Makefile

#!/usr/bin/env just --justfile
# support custom local justfile recipies
#set fallback # git worktrees
#import? 'justfile.extra' # git branches / jujitsu
# makes variables accesible as $1 $2 $@, useful for escaping variadics
set positional-arguments := true
export rootdir := justfile_directory()
export invokedir := invocation_directory()
export epoch := `date +%s`
# default interactive settings
export GUM_FILTER_HEIGHT := "15"
export FZF_DEFAULT_OPTS := "--height 15 --cycle --bind 'ctrl-a:toggle-all' " + env('FZF_DEFAULT_OPTS', "")
# deal with concurrency
export GIT := `command -v git-wait >/dev/null && echo "git-wait" || echo "git"`
# trigger a direnv reload when entering $SHELL
export DIRENV_WATCHES := ""
# try and avoid surprises via local nixpkgs overrides
export NIXPKGS_CONFIG := ""
#export NIX_PATH := "" # in case 'nixpkgs-overlay' is set here
export NIX_PATH := `echo "${NIX_PATH_ORIG:-"${NIX_PATH:-}"}"` # in case 'nixpkgs-overlay' is set here
XARGS_NL := "-d'\\n' --no-run-if-empty"
NIX_EVAL_OPTS := "--log-format raw --option warn-dirty false"
# required programs: git nix nom gum fzf tee nix-update jq fd xe sd
@_default:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep -vxE 'commit|fixup|list|build'))"
@commit *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^commit-'))" "$@"
@fixup *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^fixup-'))" "$@"
@list *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^list-'))" "$@"
@instantiate *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^instantiate-'))" "$@"
@build *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^build-'))" "$@"
@bump *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^bump-'))" "$@"
@get *args:
cd "$invokedir"; just "$(gum filter $(just --summary --unsorted | tr ' ' '\n' | grep '^get-'))" "$@"
# === info helpers ===
[no-cd]
eval-meta $attrpath=`just _a_package`:
#!/usr/bin/env -S bash -euo pipefail
main() {
nix eval {{NIX_EVAL_OPTS}} --file default.nix "$attrpath".meta --json
# nix eval {{NIX_EVAL_OPTS}} --impure --expr "with import ./. {}; { inherit ($attrpath) pname version drvPath meta; outPath_ = $attrpath.outPath; }" --json
}
if [[ -t 1 ]] && command -v fx >/dev/null; then
main | FX_COLLAPSED=true fx
else
main
fi
list-packages +$cut_args="-c1-": _packages_json
#!/usr/bin/env -S bash -euo pipefail
cachefile=/tmp/nixpkgs-packages.json.tsv
if ! [[ -s "$cachefile" && "$cachefile" -nt packages.json ]]; then
jq <packages.json 'to_entries[] | select(.value.meta.position==null|not) | [.key, .value.meta.position] | @tsv' -r \
| tr '0123456789' '9876543210' | sort | tr '0123456789' '9876543210' \
| sed -e 's#:\([0-9]*\)$#\t\1#' \
| grep . >"$cachefile"
#| sed -e "s#\t$(realpath master)/#\t#" \
fi
cut <"$cachefile" "$@"
list-packages-fname-filtered *fnames:
#!/usr/bin/env -S bash -euo pipefail
declare -a fnames=("$@")
if [[ "${#fnames[@]}" -gt 0 ]]; then
printf "%s\n" "${fnames[@]}" | just _list_packages_fname_filtered
elif [[ -t 0 ]]; then
fd . pkgs -enix -tf | fzf --reverse --multi | just _list_packages_fname_filtered
else
echo >&2 No args and no tty, reading from stdin...
just _list_packages_fname_filtered
fi
@_list_packages_fname_filtered:
xargs {{XARGS_NL}} -n 2000 just __list_packages_fname_filtered \
| tr '0123456789' '9876543210' | sort -u | tr '0123456789' '9876543210'
@__list_packages_fname_filtered +fnames:
just list-packages | grep --fixed-strings "$(printf "\t%s\t\n" "$@")" \
| grep -v $'\t'pkgs/top-level/ \
| grep -v $'\t'pkgs/applications/editors/vim/plugins/ \
| grep -v $'\t'pkgs/applications/editors/vim/plugins/ \
| grep -v $'\t'pkgs/applications/editors/vscode/extensions/default.nix \
| grep -v $'\t'pkgs/build-support/cc-wrapper/default.nix \
| grep -v $'\t'pkgs/build-support/trivial-builders/default.nix \
| grep -v $'\t'pkgs/desktops/gnome/extensions/buildGnomeExtension.nix \
| grep -v $'\t'pkgs/development/compilers/chicken/5/default.nix \
| grep -v $'\t'pkgs/development/haskell-modules/hackage-packages.nix \
| grep -v $'\t'pkgs/development/lisp-modules/imported.nix \
| grep -v $'\t'pkgs/development/lua-modules/generated-packages.nix \
| grep -v $'\t'pkgs/development/python-modules/mypy-boto3/default.nix \
| grep -v $'\t'pkgs/development/python-modules/types-aiobotocore-packages/default.nix \
| grep -v $'\t'pkgs/os-specific/linux/nvidia-x11/generic.nix \
| grep -v $'\t'pkgs/servers/home-assistant/default.nix \
| grep -v $'\t'pkgs/tools/package-management/akku/default.nix \
| grep -v $'\t'pkgs/tools/typesetting/tex/texlive/build-texlive-package.nix
list-packages-attrpath-filtered *attrpaths:
#!/usr/bin/env -S bash -euo pipefail
declare -a attrpaths=("$@")
if [[ "${#attrpaths[@]}" -gt 0 ]]; then
printf "%s\n" "${attrpaths[@]}" | just _list_packages_attrpath_filtered
elif [[ -t 0 ]]; then
fd . pkgs -enix -tf | fzf --reverse --multi | just _list_packages_attrpath_filtered
else
echo >&2 No args and no tty, reading from stdin...
just _list_packages_attrpath_filtered
fi
@_list_packages_attrpath_filtered:
tr '0123456789' '9876543210' | sort -u | tr '0123456789' '9876543210' \
| xargs {{XARGS_NL}} -n 2000 just __list_packages_attrpath_filtered
__list_packages_attrpath_filtered +attrpaths:
#!/usr/bin/env -S bash -euo pipefail
declare -a attrpaths=("$@")
attrpaths=("${attrpaths[@]/"."/"\."}")
attrpaths=("${attrpaths[@]/"*"/"\*"}")
attrpaths=("${attrpaths[@]/"+"/"\+"}")
attrpaths=("${attrpaths[@]/"$"/"\$"}")
attrpaths=("${attrpaths[@]/"("/"\("}")
attrpaths=("${attrpaths[@]/")"/"\)"}")
attrpaths=("${attrpaths[@]/#/"^"}")
attrpaths=("${attrpaths[@]/%/$'\t'}")
# printf >&1 "'%s'\n" "${attrpaths[@]}"
just list-packages | grep "$(printf "%s\n" "${attrpaths[@]}")"
list-packages-by-maintainer *github_handles: _packages_json
#!/usr/bin/env -S bash -euo pipefail
declare -a maintainers=("$@")
[[ "${#maintainers[@]}" -gt 0 ]] || readarray -td $'\n' maintainers < <( just _some_maintainers )
[[ "${#maintainers[@]}" -gt 0 ]]
#grep </tmp/nixpkgs-maintainers.tsv -F "$(printf "%s\t\n" "${maintainers[@]}")"
maintainers_json=$(printf "%s\n" "${maintainers[@]}" | jq -sR 'split("\n")|map(select(.==""|not))' -c)
jq <packages.json --argjson maintainers "$maintainers_json" 'to_entries[] | select([.value.meta.maintainers // [] | .[] | .github as $maintainer | $maintainers[] | . == $maintainer] | any) | .key' -r \
| tr '0123456789' '9876543210' | sort -u | tr '0123456789' '9876543210'
[no-cd]
@list-ripgrepped-packages +$ripgrep_args:
[[ -e .git && -e flake.nix ]] || { echo >&2 "ERROR: Not in repo root"; false; }
[[ -n "$ripgrep_args" ]] || { echo >&2 "ERROR: No ripgrep args"; false; }
rg "$@" pkgs/ -tnix -l | just _list_packages_fname_filtered
[no-cd]
@list-nix-located-packages +$nix_locate_args:
[[ -e .git && -e flake.nix ]] || { echo >&2 "ERROR: Not in repo root"; false; }
[[ -n "$nix_locate_args" ]] || { echo >&2 "ERROR: No nix-locate args"; false; }
nix-locate --top-level --regex "$@" | cut -d' ' -f1 | sd '\.out$' '' | sort -u | just _list_packages_attrpath_filtered
[no-cd]
@list-dirty-packages:
test -n "$($GIT diff HEAD --name-only)" || { echo >&2 "No unstaged dirty files found!"; false; }
$GIT diff HEAD --name-only | just _list_packages_fname_filtered
[no-cd]
@list-packages-touched-since $rev=`cd "$invokedir"; just _a_commit`:
test -n "$rev" || { echo >&2 "you must pick a revision to compare against!"; false; }
$GIT diff "$rev" --name-only | just _list_packages_fname_filtered
[no-cd]
@list-unmerged-packages:
$GIT fetch upstream ||:
$GIT log HEAD --not --remotes --oneline | cut -d' ' -f2- | cut -d: -f1 | grep -vE '(^treewide|[, ])' | sort -u
# === build helpers ===
@build-packages-fname-filtered *fnames:
cd "$invokedir"; just list-packages-fname-filtered "$@" | cut -f1 | xargs {{XARGS_NL}} just build-packages
@build-ripgrepped-packages $ripgrep_arg $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-ripgrepped-packages "$ripgrep_arg" | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just build-packages
@build-nix-located-packages $nix_locate_arg $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-nix-located-packages "$nix_locate_arg" | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just build-packages
@build-dirty-packages $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-dirty-packages | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just build-packages
@instantiate-dirty-packages $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-dirty-packages | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just instantiate-packages
@build-packages-touched-since $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-packages-touched-since | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just build-packages
@instantiate-packages-touched-since $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-packages-touched-since | cut -f1 | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just instantiate-packages
@build-unmerged-packages $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-unmerged-packages | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just build-packages
@instantiate-unmerged-packages $attr_prefix="" $attr_suffix="" +$extra_args="":
[[ -n "$extra_args" ]] && export _JUST_NIX_INSTANTIATE_ARGS="$(shift; shift; printf " %q" "$@")"; \
cd "$invokedir"; just list-unmerged-packages | xargs {{XARGS_NL}} printf "${attr_prefix//%/%%}"'%s'"${attr_suffix//%/%%}\n" | xargs {{XARGS_NL}} just instantiate-packages
#
# _JUST_NIX_INSTANTIATE_ARGS="--system darwin" # TODO: remove, use for unfree or cross intead
[no-cd]
instantiate-packages +$attrpaths="":
#!/usr/bin/env -S bash -euo pipefail
test -n "${attrpaths:-}" || set -- $(just _some_packages)
attrpaths=("$@")
export NIXPKGS_ALLOW_UNFREE=1
if gum confirm "Allow insecure?"; then
export NIXPKGS_ALLOW_INSECURE=1
fi
readarray -td $'\n' systems < <( just _some_systems )
for system in "${systems[@]}"; do
just _instantiate_packages "$system" "${attrpaths[@]}"
done
[no-cd]
instantiate-packages-extra-suffixes +$attrpaths="":
#!/usr/bin/env -S bash -euo pipefail
test -n "${attrpaths:-}" || set -- $(just _some_packages)
attrpaths=("$@")
[[ "${#attrpaths[@]}" -ne 0 ]]
suffixes=(
"%s"
"%s.src"
"%s.patches"
"%s.passthru.tests"
"%s.cargoDeps"
)
readarray -td $'\n' selected_suffixes < <(
# gum choose --no-limit "${suffixes[@]}"
printf "%s\n" "${suffixes[@]}" | fzf --layout=reverse --multi
)
[[ "${#selected_suffixes[@]}" -ne 0 ]]
readarray -td $'\n' selected_attrpaths < <(
for suffix in "${selected_suffixes[@]}"; do
printf "$suffix\n" "${attrpaths[@]}"
done
)
just instantiate-packages "${selected_attrpaths[@]}"
[no-cd]
_instantiate_packages $systems +$attrpaths:
#!/usr/bin/env -S bash -euo pipefail
# slower than normal nix-instantiate, but handles bad attrpaths, TODO: parallel eval?
# supports envvar _JUST_NIX_INSTANTIATE_CACHE
# supports envvar _JUST_NIX_INSTANTIATE_ARGS
declare -a attrpaths=("${@:2}")
if [[ -d "${_JUST_NIX_INSTANTIATE_CACHE:-}" ]]; then
mkdir -p "$_JUST_NIX_INSTANTIATE_CACHE"/{roots,paths}
worker() {
local attrpath="$1"
if [[ -s "$_JUST_NIX_INSTANTIATE_CACHE/paths/$attrpath.drv" ]]; then
cat "$_JUST_NIX_INSTANTIATE_CACHE/paths/$attrpath.drv"
else
NIXPKGS_ALLOW_UNFREE=1 nice -n5 nix-instantiate . -A "$attrpath" \
--system "$system" \
${_JUST_NIX_INSTANTIATE_ARGS:-} \
--add-root "$_JUST_NIX_INSTANTIATE_CACHE/roots/$attrpath.drv" \
| tee "$_JUST_NIX_INSTANTIATE_CACHE/paths/$attrpath.drv"
fi
}
for system in $systems; do
export system
printf "%s\n" "${attrpaths[@]}" | grep . | \
xe -j0 -s "$(declare -f worker); worker \"\$@\""
done
else
export system
for system in $systems; do
printf "%s\n" "${attrpaths[@]}" | grep . | \
xe -j0 -s 'NIXPKGS_ALLOW_UNFREE=1 nix-instantiate . -A "$1" --system "$system" '"${_JUST_NIX_INSTANTIATE_ARGS:-}"''
done
fi
[no-cd]
profile *args:
#!/usr/bin/env -S bash -euo pipefail
declare -a args=("$@")
if [[ "${#args[@]}" -eq 0 ]]; then
args=(. -A "$(just _a_package)")
fi
set -x
NIX_SHOW_STATS=1 NIX_COUNT_CALLS=1 nix-instantiate "${args[@]}"
# _JUST_NIX_BUILD_ARGS='--check'
# _JUST_NIX_BUILD_ARGS='-j0 --builders "@/etc/nix/machines; ssh://pederbs@heid.idi.ntnu.no x86_64-linux - 24 5 big-parallel"'
[no-cd]
build-packages *$attrpaths:
#!/usr/bin/env -S bash -euo pipefail
[[ "$#" -gt 0 ]] || set -- $(just _some_packages)
[[ "$#" -gt 0 ]]
export JUST_SYSTEM="$(just _a_system)"
[[ -n "$JUST_SYSTEM" ]]
export NIXPKGS_ALLOW_UNFREE=1
if gum confirm "Allow insecure?"; then
export NIXPKGS_ALLOW_INSECURE=1
fi
if [[ -z "${_JUST_NIX_BUILD_ARGS:-}" ]]; then
_JUST_NIX_BUILD_ARGS="$(gum choose --no-limit -- "-j0" "--check" | tr '\n' ' ')"
export _JUST_NIX_BUILD_ARGS
fi
just _build_packages results "$@"
[no-cd]
_build_packages $outdir +$attrpaths:
just __build_packages "$(just _a_system)" "$@"
[no-cd]
__build_packages $system $outdir +$attrpaths:
#!/usr/bin/env -S bash -euo pipefail
# hint: supports _JUST_NIX_BUILD_ARGS
# hint: supports _JUST_NIX_INSTANTIATE_ARGS
test -z "${_JUST_NIX_BUILD_ARGS:-}" || echo >&2 "_JUST_NIX_BUILD_ARGS = $_JUST_NIX_BUILD_ARGS"
test -z "${_JUST_NIX_INSTANTIATE_ARGS:-}" || echo >&2 "_JUST_NIX_INSTANTIATE_ARGS = $_JUST_NIX_INSTANTIATE_ARGS"
test -d "$outdir" && {
rm -rf "$outdir"/.gcroot
rm -rf "$outdir"/.views
fd . "$outdir" --type l -X rm -v
fd \\\.log$ "$outdir" --type f -X rm -v
}
declare -a attrpaths=("${@:3}")
mkdir -p "$outdir/.gcroot"
mkdir -p "$outdir/.views/"{succeeded,failed}
export _JUST_NIX_INSTANTIATE_CACHE=$(mktemp -d)
export NOTFOUNDDIR="$(mktemp -d)"; touch "$NOTFOUNDDIR"/no-eval
# set -x
just _instantiate_packages "$system" "${attrpaths[@]}" | tee >(command cat >&2) \
| while IFS=! read path output; do printf "%s\n" "$(realpath "$path")${output:+!"$output"}"; done \
| xargs {{XARGS_NL}} nom-build --keep-going --no-out-link ${_JUST_NIX_BUILD_ARGS:-} ||:
# | eval xargs nom-build --keep-going --no-out-link ${_JUST_NIX_BUILD_ARGS:-} ||:
worker() {
local attrpath="$1"
local dst="$outdir/$attrpath"
local dst2a="$outdir/.views/succeeded/$attrpath"
local dst2b="$outdir/.views/failed/$attrpath"
local gcroot="$outdir/.gcroot/$attrpath" # workaround since .drv!dev will always append "-dev" to --out-path
local drvpath=$( just _instantiate_packages "$system" "$attrpath" )
set -x
if [[ -n "$drvpath" ]]; then
local inStoreDrvPath # eww, why doesn't the !output syntax work for out of store symlinks?
if [[ "$drvpath" =~ '!' ]]; then
inStoreDrvPath="$(realpath "$(cut -d! -f1 <<<"$drvpath")")!$(cut -d! -f2 <<<"$drvpath")"
else
inStoreDrvPath="$(realpath "$drvpath")"
fi
nice -n5 nix-build "$inStoreDrvPath" -j0 --option builders "" --option substitute false --out-link "$gcroot" >&/dev/null ||:
if [[ "$drvpath" =~ '!' ]]; then
# :(
gcroot="$gcroot-$(cut -d! -f2 <<<"$drvpath")"
fi
if [[ -e "$gcroot" ]]; then
ln -s "$(readlink "$gcroot")" $dst
fi
fi
# local outpaths=$( nix-store -q --outputs "$drvpath" ) # doesn't gcroot, some outputs may not be pulled from builders
if [[ -L "$dst" ]]; then
nice -n5 nix log $(readlink "$dst") > "$dst".log 2>/dev/null ||:
# nice -n5 nix log --option substituters "" $(readlink "$dst") > "$dst".log 2>/dev/null ||:
ln -sr "$dst" "$dst2a"
ln -sr "$dst".log "$dst2a".log
else
if [[ -z "$drvpath" ]]; then
ln -s "$NOTFOUNDDIR"/no-eval "$dst"
ln -s "$NOTFOUNDDIR"/no-eval "$dst2b"
nice -n5 nix-instantiate . -A "$attrpath" >& "$dst.log" # a third time...
ln -sr "$dst".log "$dst2b".log
else
ln -s /build-failure-"$attrpath" "$dst"
ln -s /build-failure-"$attrpath" "$dst2b"
nice -n5 nix log --option substituters "" ".#$attrpath" --system "$system" ${_JUST_NIX_INSTANTIATE_ARGS:-} > "$dst".log 2>/dev/null ||:
ln -sr "$dst".log "$dst2b".log
fi
fi
}
printf "%s\n" "${attrpaths[@]}" | xe -j0 -s "set -euo pipefail; $(declare -f worker); worker \"\$@\"" ||:
# echo -e "#!/usr/bin/env bash\ntest -f flake.nix || cd ..; env _JUST_NIX_INSTANTIATE_ARGS=\"\$*\" just __build_packages "$system" \"$outdir\"" $attrpaths > "$outdir"/_rerun.sh
cat <<-EOF >"$outdir"/_rerun.sh
#!/usr/bin/env bash
while [[ ! -f flake.nix ]]; do
cd ..
done
set -v
_JUST_NIX_INSTANTIATE_ARGS="\$*" just __build_packages "\${1:-"$system"}" $(printf " %q" "$outdir" "${attrpaths[@]}")
EOF
chmod +x "$outdir"/_rerun.sh
fd . "$outdir" -l
# TODO: use in 'bump'
[no-cd]
build-package-sources *packages:
#!/usr/bin/env -S bash -euo pipefail
packages=("$@")
[[ "${#packages[@]}" -gt 0 ]] || readarray -td $'\n' packages < <( just _some_packages )
just _build_package_sources "$(just _a_system)" "${packages[@]}"
[no-cd]
_build_package_sources $system +packages:
#!/usr/bin/env -S bash -euo pipefail -x
[[ -e .git && -f flake.nix ]] || { printf >&2 "%s\n" "ERROR: not in repo root!"; false; }
declare packages=("${@:2}")
# TODO: allow selecting different names than result-src and results-src-writeable
just __build_packages "$system" results-src "${packages[@]/%/.src}"
[[ -d results-src-writeable ]] && rm -rf results-src-writeable ||:
mkdir -p results-src-writeable
for result in results-src/* ; do
[[ -L "$result" ]] || continue
result_writeable=results-src-writeable/"$(basename "$result")"
mkdir -p "$result_writeable"
if [[ -d "$(readlink "$result")" ]]; then
rsync -rxL --chmod=ugo+w "$result/" "$result_writeable/" ||:
#chmod -R +w "$result_writeable/"
elif [[ -f "$(readlink "$result")" ]]; then
atool "$(readlink "$result")" --extract-to="$result_writeable/" ||:
if [[ $(ls --almost-all "$result_writeable" | wc -l ) -eq 1 ]] && test -d "$result_writeable"/*; then
mv "$result_writeable"{,-old}
mv "$result_writeable"-old/* "$result_writeable"
rmdir "$result_writeable"-old
fi
fi
(
# todo: should i eval nix and query for upstream remote and ref?
cd "$result_writeable"
$GIT init
$GIT add .
$GIT commit -m "Base" >/dev/null
) ||:
done
{
# printf "#!/usr/bin/env -S nom-build\n"
printf "#!/usr/bin/env -S nom build -f\n"
printf "let pkgs = import ./. { }; in {\n"
for package in "${packages[@]}"; do
# printf " # ./build.nix -A %q" "$package"
printf " # ./build.nix %q\n" "$package"
printf " %s = pkgs.%s.overrideAttrs { src = ./results-src-writeable/%s.src; };\n" "$package" "$package" "$package"
done
printf "}\n"
# printf "# ./build.nix$(printf " -A %q" "${packages[@]}")\n"
printf "# ./build.nix$(printf " %q" "${packages[@]}")\n"
printf "# ./build.nix\n"
} >build.nix
chmod +x build.nix
# TODO: redesign or drop
@build-pr-packages $pr=`just _a_pr` $merge=`gum choose --header="which refs/pull/<id>/xxx ?" merge head` $attrpaths=`just _some_packages` $args=`gum choose --no-limit -- -j0 "--system "{aarch64,x86_64}-{darwin,linux} --rebuild`:
printf "github:nixos/nixpkgs/refs/pull/"$(just _sanitize_pr_url "$pr")"/$merge#%s\n" $attrpaths | xargs {{XARGS_NL}} echo + nom build $args
(printf "github:nixos/nixpkgs/refs/pull/"$(just _sanitize_pr_url "$pr")"/$merge#%s\n" $attrpaths | xargs {{XARGS_NL}} nom build $args) ||:
printf "github:nixos/nixpkgs/refs/pull/"$(just _sanitize_pr_url "$pr")"/$merge#%s\n" $attrpaths | xargs {{XARGS_NL}} echo + nom build $args
# === commit helpers ===
[no-cd]
@commit-staged *$message:
test -n "$($GIT diff HEAD --name-only --staged)" || ! echo >&2 "No files are staged!" || false
$GIT diff HEAD --name-only --staged | sort -u | xe nixfmt --check
$GIT -c commit.template=<(git diff HEAD --name-only --staged | just _list_packages_fname_filtered | cut -f1 | just _attrpaths_2_aliases | xargs {{XARGS_NL}} printf "%s: ${*//%/%%}\n") commit && git show
[no-cd]
commit-dirty-packages +$message=`gum input --placeholder="commit message, (attrpath: this message)"`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "$message" ]]
if ! $GIT ls-files --modified | sort -u | xe -j0 nixfmt --check; then
if gum confirm "Run 'just format-files-dirty'?"; then
just format-files-dirty
else
false
fi
fi
just list-dirty-packages |
while read attrpath position row; do
[[ -f "$position" ]] || continue
$GIT diff -s --exit-code "$position" || (
set -x
$GIT add "$position"
$GIT commit -m "$(just _attrpaths_2_aliases <<<"$attrpath"): $*"
)
done
[no-cd]
fixup-commit:
#!/usr/bin/env -S bash -euo pipefail
# TODO: list commits first
test -n "$($GIT diff --name-only --staged)" || {
$GIT ls-files --modified --others --exclude-standard |
grep -v ^results- |
fzf --layout=reverse --multi |
xe $GIT add --patch
}
test -n "$($GIT diff --name-only --staged)" || {
echo >&2 Nothing is staged!
false
}
just fixup-commit-staged
[no-cd]
fixup-commit-staged commit=`cd "$invokedir"; just _a_commit`:
#!/usr/bin/env -S bash -euo pipefail
test -n "{{ commit }}" # just exit if no selection was made
test -n "$($GIT diff --name-only --staged)" || { echo >&2 Nothing is staged!; false; }
$GIT diff --staged
echo; gum format "# ========= into ========="; echo
$GIT log {{ commit }} -n1
gum confirm
$GIT commit --fixup={{ commit }}
GIT_SEQUENCE_EDITOR=true $GIT rebase -i --autostash --autosquash "$($GIT log -n1 --pretty=%P {{ commit }})"
rebase-commits commit=`cd "$invokedir"; just _a_commit`:
cd "$invokedir"; $GIT rebase -i --autostash --autosquash "$($GIT log -n1 --pretty=%P {{ commit }})"
[no-cd]
bisect-eval $attrpath=`just _a_package` *_:
#!/usr/bin/env -S bash -euo pipefail
tmpfile=$(mktemp)
hello
printf "#!/usr/bin/env -S bash -euxo pipefail\nnix-instantiate --json --strict --eval --system %q . -A %q" "$(just _a_system)" "$attrpath" > "$tmpfile"
chmod +x "$tmpfile"
just bisect-script "$tmpfile" "${@:2}"
[no-cd]
bisect-build $attrpath=`just _a_package` *_:
#!/usr/bin/env -S bash -euo pipefail
tmpfile=$(mktemp)
# printf "#!/usr/bin/env -S bash -euxo pipefail\nnix-build --no-out-link $(gum choose -- "" "-j0") --system %q . -A %q" "$(just _a_system)" "$attrpath" > "$tmpfile"
printf "#!/usr/bin/env -S bash -euxo pipefail\nnom-build --no-out-link $(gum choose -- "" "-j0") --system %q . -A %q" "$(just _a_system)" "$attrpath" > "$tmpfile"
chmod +x "$tmpfile"
just bisect-script "$tmpfile" "${@:2}"
[no-cd]
bisect-script $repro_script $bad_commit=`cd "$invokedir"; HEADER="Bad commit" just _a_commit` $good_commit=`cd "$invokedir"; HEADER="Good commit" just _a_commit`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "$repro_script" ]]
[[ -n "$good_commit" ]]
[[ -n "$bad_commit" ]]
[[ -x "$repro_script" ]] || ! echo >&2 "ERROR: '$repro_script' is not an executable file!" || false
declare -a args=()
declare -a possible_args=(
"--first-parent Follow only the first parent commit upon seeing a merge commit."
"--no-checkout Do not checkout the new working tree, instead just update BISECT_HEAD "
)
readarray -td $'\n' args < <(gum choose --no-limit -- "${possible_args[@]}" | cut -d' ' -f1)
(set -x
$GIT bisect start "${args[@]}" "$bad_commit" "$good_commit" --
$GIT bisect run "$repro_script"
)
echo >&2 "Continue with '$GIT bisect run \"$repro_script\"'"
echo >&2 "Conclude with 'git bisect reset'"
# === pr helper ===
[no-cd]
push-new-pr:
#!/usr/bin/env -S bash -euo pipefail -x
# TODO: verify "origin" is a nixpkgs fork and not NixOS/nixpkgs
if gum confirm --default=no "Test merging into upstream branches?"; then
just test-merge || gum confirm --default=no "Continue?"
fi
# TODO: can i retrieve what the upstream tracking base is for the current branch/worktree?
declare base
base="$(just _a_upstream_release_branch "Base?" | cut -d/ -f2-)"
[[ -n "$base" ]]
declare title
title="$(just _a_commit_title ||:)"
if [[ "$base" != "master" && "$base" != "staging" && "$base" != staging-next ]]; then
title="[$base] $title"
fi
title="$(gum input --placeholder="foobar: did a thing" --value="$title" ||:)"
$GIT -c push.autoSetupRemote=true push origin
if [[ -n "$title" ]]; then
gh pr create --base="$base" --title="$title"
else
gh pr create --base="$base"
fi
if gum confirm "Enqueue nixpkgs-review?"; then
sleep 5
pr_number="$(gh pr list --author @me | column -s$'\t' -t | gum choose | cut -d' ' -f1)"
[[ -n "$pr_number" ]]
just enqueue-nixpkgs-review "$pr_number"
fi
# === speed worktrees ===
bump-new-worktree *packages:
#!/usr/bin/env -S bash -euo pipefail
declare -a packages=("$@")
[[ "${#packages[@]}" -gt 0 ]] || readarray -td $'\n' packages <<<"$( just _some_packages )"
[[ "${#packages[@]}" -gt 0 ]]
export JUST_SYSTEM="$(just _a_system)"
gum confirm --default=no "Check versions on all branches?" && just get-versions "${packages[0]}" ||: # TODO: timeout?
worktree=$(just _new_worktree "$(gum confirm "Use tmp worktree?" && echo tmp-bump || echo bump)" "$(printf "%s\n" "${packages[0]}" | rev | cut -d. -f1 | rev)")
[[ -n "$worktree" ]]
[[ -d "$worktree" ]]
cd "$worktree"
just bump-here "${packages[@]}"
NIXPKGS_ALLOW_UNFREE=1 exec just _enter_interactive_shell
[no-cd]
bump-here *packages:
#!/usr/bin/env -S bash -euo pipefail
[[ -e .git && flake.nix ]]
declare -a packages=("$@")
[[ "${#packages[@]}" -gt 0 ]] || readarray -td $'\n' packages <<<"$( just _some_packages )"
[[ "${#packages[@]}" -gt 0 ]]
declare -a package_aliases=()
readarray -td $'\n' package_aliases <<<"$( printf "%s\n" "${packages[@]}" | just _attrpaths_2_aliases )"
[[ "${#package_aliases[@]}" -gt 0 ]] || package_aliases=("${#packages[@]}")
[[ "${#package_aliases[@]}" -gt 0 ]]
system="$(just _a_system)"
config1=(
env
NIXPKGS_ALLOW_UNFREE=1
NIXPKGS_ALLOW_INSECURE=1
)
config2=(
"${config1[@]}"
NIXPKGS_ALLOW_BROKEN=1
)
printf "%s.src\n" "${package_aliases[@]}" | "${config2[@]}" xargs {{XARGS_NL}} just __build_packages "$system" results-src-old ||: # TODO: unpack?
for package in "${package_aliases[@]}"; do
if nix eval {{NIX_EVAL_OPTS}} --file default.nix "$package".passthru.updateScript >&/dev/null; then
HEAD=$($GIT rev-parse HEAD)
"${config2[@]}" nix-update "$package" --use-update-script --update-script-args "--argstr skip-prompt true" --commit
if [[ $($GIT rev-parse HEAD) = "$HEAD" ]]; then
echo "no commit found, trying without the updateScript..."
$GIT restore .
"${config2[@]}" nix-update "$package" --commit || true
fi
else
"${config2[@]}" nix-update "$package" --commit || true
fi
done
set +e
printf "%s.src\n" "${package_aliases[@]}" | "${config2[@]}" xargs {{XARGS_NL}} just __build_packages "$system" results-src-new # TODO: unpack?
"${config1[@]}" just __build_packages "$system" results "${packages[@]}"
# TODO: filter non-existing tests:
printf "%s.tests\n" "${packages[@]}" | "${config1[@]}" _JUST_NIX_BUILD_ARGS="-j1" xargs {{XARGS_NL}} just __build_packages "$system" results-tests
printf "HEAD^%s " $(seq 0 $(( "${#package_aliases[@]}" - 1 ))) | xe $GIT show
fd . -l results results-tests --max-depth 1
# test -L result && fd . result --type x --color=always | tee update-executables.txt
# $GIT show --name-only --pretty="" | xe statix fix
$GIT diff
printf "\n"
printf "delta results-src-{old,new}/%s.src/.\n" "${package_aliases[@]}"
printf "\n"
printf > delta-cmds.sh '#!/usr/bin/env bash\n'
printf >>delta-cmds.sh 'tail "$0" -n+3 | bat --style plain -l bash; exit 1\n'
printf >>delta-cmds.sh "delta results-src-{old,new}/%s.src/.\n" "${package_aliases[@]}"
fix *packages:
#!/usr/bin/env -S bash -euo pipefail
declare packages=("$@")
[[ "${#packages[@]}" -gt 0 ]] || packages=($(just _some_packages))
[[ "${#packages[@]}" -gt 0 ]] || { printf >&2 "%s\n" "ERROR: no packages chosen..."; false; }
export JUST_SYSTEM="$(just _a_system)"
just open-package-urls "${packages[0]}" ||:
cd "$(just _new_worktree "$(gum confirm "Use tmp worktree?" && echo tmp-fix || echo fix)" "$(echo "${packages[0]}" | rev | cut -d. -f1 | rev)")"
just _fix "${packages[@]}" ||:
if gum confirm "Try to bump?" --default=no; then
rm -rf results-src
just bump-here "${packages[@]}"
fi
exec just _enter_interactive_shell
[no-cd]
_fix +packages:
#!/usr/bin/env -S bash -euo pipefail
[[ -e .git && -f flake.nix ]] || { printf >&2 "%s\n" "ERROR: not in repo root!"; false; }
declare packages=("$@")
export JUST_SYSTEM="$(just _a_system)"
just build-package-sources "${packages[@]}"
NIXPKGS_ALLOW_UNFREE=1 just build-packages "${packages[@]}" ||:
if command -v bat >/dev/null;
then bat build.nix --style header-filename
else cat build.nix
fi
pr $number=`just _a_pr`:
#!/usr/bin/env -S bash -euo pipefail
number=$(just _sanitize_pr_url "$number")
# TODO: support --onto
do_rebase() {
local upstream_branch="$1" # "upstream/master"
local remote="$(cut <<<"$upstream_branch" -d'/' -f1)"
local branch="$(cut <<<"$upstream_branch" -d'/' -f2)"
# TODO: gitignore ./checkout-upstream-branch.sh
printf "git checkout %q\n" "$(git rev-parse --abbrev-ref HEAD)" > checkout-upstream-branch.sh
chmod +x checkout-upstream-branch.sh
(set -x;
$GIT checkout -b pr-"$number"-rebased-"$remote"-"$branch-{{ epoch }}" ||:
$GIT pull --rebase "$remote" "$branch" || $GIT rebase --abort
) || echo >&2 "retcode: $?" ||:
}
if [[ -d prs/pr-"$number" ]]; then
cd prs/pr-"$number"
if gum confirm --default=no "Force pull?"; then
upstream_branch=$( just _a_upstream_release_branch "Rebase?" "" )
[[ ! -e ./checkout-upstream-branch.sh ]] || rm ./checkout-upstream-branch.sh
(set -x; gh pr checkout "$number" --force)
[[ -z "$upstream_branch" ]] || do_rebase "$upstream_branch"
fi
else
upstream_branch=$( just _a_upstream_release_branch "Rebase?" "" )
(cd master;
$GIT worktree prune
# (set -x; $GIT worktree add -b just-nixpkgs-pr-"$number"-tmp ../prs/pr-"$number")
declare pull_json
pull_json="$(gh api repos/NixOS/nixpkgs/pulls/382957)"
git fetch upstream "$(jq <<<"$pull_json" '.base.ref' -r)"
(set -x; $GIT worktree add ../prs/pr-"$number" "$(jq <<<"$pull_json" '.base.sha' -r)")
)
cd prs/pr-"$number"
(set -x; gh pr checkout "$number")
# git branch -D just-nixpkgs-pr-"$number"-tmp
[[ -z "$upstream_branch" ]] || do_rebase "$upstream_branch"
fi
exec just _enter_interactive_shell
@pr-comment-diff:
cd "$invokedir"; just _pr_post_diff comment
@pr-review-diff:
cd "$invokedir"; just _pr_post_diff "review $(gum choose --ordered -- --comment --request-changes --approve)"
@_pr_post_diff mode:
test "prs" = "$(cd "$invokedir" ; $GIT rev-parse --show-toplevel | rev | cut -d/ -f2 | rev)"
test -n "$(cd "$invokedir"; $GIT diff --staged)" || { echo no changes staged; cd "$invokedir"; $GIT add --patch; true; }
test -n "$(cd "$invokedir"; $GIT diff --staged)" || { echo no changes staged; false; }
cd "$invokedir"; \
NUMBER="$($GIT rev-parse --show-toplevel | rev | cut -d/ -f1 | rev | cut -d- -f2)"; \
FNAME="$(mktemp --suffix=.md)"; \
echo "NUMBER=$NUMBER" "FNAME=$FNAME"; \
>>"$FNAME" echo; \
>>"$FNAME" echo '<details>'; \
>>"$FNAME" echo '<summary>:clipboard: proposed patch</summary>'; \
>>"$FNAME" echo; \
>>"$FNAME" echo '```patch'; \
>>"$FNAME" $GIT diff --staged; \
>>"$FNAME" echo '```'; \
>>"$FNAME" echo; \
>>"$FNAME" echo '</details>'; \
>>"$FNAME" echo; \
>>"$FNAME" echo '_How to apply (pick either):_'; \
>>"$FNAME" echo; \
>>"$FNAME" echo 'a. `curl -L "'"$(git diff --staged | gh gist create -f pr-$NUMBER.patch -)"'/raw" | git apply`'; \
>>"$FNAME" echo 'b. copy the patch above, run `git apply`, paste (typically `ctrl-shift-v`), press enter, then end the input with `ctrl-d`'; \
"$EDITOR" "$FNAME"; \
test -s "$FNAME" && bat --language markdown --style plain --pager never "$FNAME" && gum confirm && gh pr {{ mode }} "$NUMBER" --body-file "$FNAME"; \
rm -v "$FNAME"
# TODO: git nomad?
remote-branch $remote_ref=`just _a_remote_branch origin | cut -d/ -f2-`:
#!/usr/bin/env -S bash -euo pipefail
branch_dir=$(cut <<<"$remote_ref" -d- -f1)
branch_base=$(cut <<<"$remote_ref" -d- -f2-)
cd master
$GIT worktree add --track ../"$branch_dir/$branch_base" -b "$remote_ref" origin/"$remote_ref"
cd ../"$branch_dir/$branch_base"
exec just _enter_interactive_shell
# === worktrees ===
# TODO: onto release-xx.yy doesn't work
# TODO: python-updates
checkout-commit-in-worktree $commit=`just _a_commit`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${commit:-}" ]]
if [[ -d tmp/commit-"$commit" ]]; then
echo >&2 "Commit already checked out, cd'ing there..."
else
(
cd master
$GIT worktree prune
# TODO: fetch the commit from upstream if it doesn't exist?
# TODO: support github /commit/ urls?
$GIT worktree add ../tmp/commit-"$commit" "$commit"
)
fi
cd tmp/commit-"$commit"
exec just _enter_interactive_shell
@new-worktree *args:
cd "$(just _new_worktree "$@")"; exec just _enter_interactive_shell
@_a_wt_type:
gum choose feat fix init bump doc migrate backport drop tmp tmp-bump tmp-fix
@_a_wt_name:
gum input --placeholder="Branch name?"
_new_worktree $type=`just _a_wt_type` $name=`just _a_wt_name` $base=`just _a_upstream_release_branch "Base?"` $onto=`just _a_upstream_release_branch "Onto?" ""`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "$type" ]]
[[ -n "$name" ]]
name="$(printf "%s" "$name" | tr '[:space:]/' -- | tr -s -)"
just _mk_worktree 1>&2 \
"$type-$name-{{ epoch }}" \
"$type/$name-{{ epoch }}" \
"$base" \
"$onto"
echo "$type/$name-{{ epoch }}"
_mk_worktree $name $dir $base="upstream/master" $onto="":
#!/usr/bin/env -S bash -euo pipefail -x
[[ -n "$name" ]]
[[ -n "$dir" ]]
[[ -n "$base" ]]
remote="$(cut -d/ -f1 <<<"$base")"
branch="$(cut -d/ -f2- <<<"$base")"
# TODO: use upstream/master/?
cd master
$GIT worktree prune
$GIT fetch "$remote" "$branch"
#$GIT branch "$name" "$branch" --no-track
$GIT branch "$name" "$base" --no-track
$GIT worktree add ../"$dir" "$name"
cd ../"$dir"
# TODO: use this to determine base instead of using rebase-onto: baserev="$(git merge-base "$base" "$onto")"
$GIT pull --rebase "$remote" "$branch"
[[ -z "$onto" ]] || just rebase-onto HEAD "$onto" # TODO: resolve the shared ancestor rev and make the worktree with it as base instead?
cherry-pick-commits-here *commits:
#!/usr/bin/env -S bash -euo pipefail -x
declare -a commits=("$@")
[[ "${#commits[@]}" -gt 0 ]] || readarray -td $'\n' commits <<<"$( cd "$invokedir"; GIT_LOG_ALL=1 just _some_commits | tac )"
[[ "${#commits[@]}" -gt 0 && -n "${commits[*]}" ]]
if gum confirm 'Use -x? Will append a line that says "(cherry picked from commit ...)"'; then
commits=(-x "${commits[@]}")
fi
git cherry-pick "${commits[@]}"
cherry-pick-commits-into-new-worktree *commits:
#!/usr/bin/env -S bash -euo pipefail
declare -a commits=("$@")
[[ "${#commits[@]}" -gt 0 ]] || readarray -td $'\n' commits <<<"$( cd "$invokedir"; just _some_commits | tac )"
[[ "${#commits[@]}" -gt 0 && -n "${commits[*]}" ]]
proposed_name="$(
git -C "$invokedir" show --oneline --no-patch "${commits[0]}" |
cut -d' ' -f2- | cut -d: -f1 | rev | cut -d. -f1 | rev
)"
if gum confirm 'Use -x? Will append a line that says "(cherry picked from commit ...)"'; then
commits=(-x "${commits[@]}")
fi
worktree="$(just _new_worktree "$(just _a_wt_type)" "$(gum input --placeholder="Branch name?" --value="$proposed_name")")"
[[ -n "$worktree" ]]
cd "$worktree"
git cherry-pick "${commits[@]}" || echo >&2 "ERROR: Cherry pick failed!"
exec just _enter_interactive_shell
pop-commits-to-new-worktree $commits=`cd "$invokedir"; just _some_commits`:
#!/usr/bin/env -S bash -euo pipefail
test -n "$commits" || { echo >&2 "no commits were selected!"; false;}
# we make two nasty assumption here:
# * the last commit passed in is also the topologically oldest one in the git history
# * the revs in the interactive rebase are just as short or longer than those returned by 'just _some_commits'
type="$(just _a_wt_type)"
name="$(
cd "$invokedir";
git show --oneline --no-patch "$(head -n1 <<<"$commits")" |
cut -d' ' -f2- | cut -d: -f1 | rev | cut -d. -f1 | rev
)"
cd "$(
just _new_worktree "$type" "$(gum input --placeholder="Branch name?" --value="$name")"
)"
if (tac <<<"$commits" | xargs {{XARGS_NL}} git cherry-pick); then
(
cd "$invokedir"
EDITOR="sed -i $(xargs {{XARGS_NL}} <<<"$commits" printf " -e 's/^pick %s/#/g'")" \
git rebase "$(tail -n1 <<<"$commits")"^^ -i
)
git log -n "$(wc -l <<<"$commits" )"
exec just _enter_interactive_shell
else
echo >&2 "The commits have not been popped."
git status
echo >&2 "The commits have not been popped."
exec just _enter_interactive_shell
fi
[no-cd]
@_rebase_onto $onto:
[[ -n "$onto" ]]
$GIT fetch upstream "$onto"
$GIT rebase --onto upstream/"$onto"...HEAD upstream/master --autostash
[no-cd]
rebase-onto $base=`just _a_upstream_release_branch "Base?" HEAD` $onto=`just _a_upstream_release_branch "Onto?"`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "$onto" ]]
if [[ "$base" != HEAD ]] ; then
remote="$(cut -d/ -f1 <<<"$base")"
branch="$(cut -d/ -f2- <<<"$base")"
(set -x; $GIT fetch "${remote:-upstream}" "$branch")
fi
if [[ "$onto" != HEAD ]] ; then
remote="$(cut -d/ -f1 <<<"$onto")"
branch="$(cut -d/ -f2- <<<"$onto")"
(set -x; $GIT fetch "${remote:-upstream}" "$branch")
fi
# $GIT rebase --onto upstream/"$onto"...HEAD upstream/master --autostash
$GIT rebase --onto "$onto"..."$base" $base --autostash
# fix periodic merge conflicts
fix-periodic-merge-conflict $from=`just _a_upstream_release_branch "From?"` $to=`just _a_upstream_release_branch "To?"`:
cd "$invokedir"; $GIT fetch upstream "$from"
cd "$invokedir"; $GIT fetch upstream "$to"
cd "$invokedir"; $GIT worktree add -b fix-merge-conflict-"$from"-to-"$to"-{{ epoch }} ../fix/merge-conflict-"$from"-to-"$to"-{{ epoch }} upstream/"$to"
cd fix/merge-conflict-"$from"-to-"$to"-{{ epoch }}; $GIT merge upstream/"$from" || true
cd fix/merge-conflict-"$from"-to-"$to"-{{ epoch }}; $GIT status
@echo "Cheatsheet:"
@echo " $GIT ls-files --modified | sort -u | xe -N0 $GIT reset"
@echo " $GIT commit"
@echo " $GIT push upstream HEAD:$to"
cd fix/merge-conflict-"$from"-to-"$to"-{{ epoch }}; exec just _enter_interactive_shell
# === setup ===
# setup or update master and staging++
setup:
#!/usr/bin/env -S bash -euo pipefail
verbose() ( set -x; "$@"; )
if [[ ! -e master/.git ]]; then
gh_user=$(gum input \
--header "git clone git@github.com:< username >/nixpkgs.git" \
--value="$(
if command -v gh >/dev/null && gh auth status >&/dev/null; then
gh api user --jq .login
else
whoami
fi
)"
)
$GIT clone "git@github.com:${gh_user}/nixpkgs.git" master
[[ -e master/.git ]]
fi
cd master
if ! $GIT remote get-url upstream >&/dev/null; then
verbose $GIT remote add upstream "https://github.com/NixOS/nixpkgs.git"
fi
# TODO: check the mtime on the HEAD file instead?
if [[ $(( "$epoch" - "$(verbose $GIT log --oneline --format="%ct" HEAD -n1)" )) -gt $(( 60*60*24 )) ]]; then
verbose $GIT pull --rebase --autostash upstream master >&2
fi
add_upstream() (
local branch="$1"
if [[ ! -d ../upstream/"$branch" ]]; then
verbose $GIT fetch upstream "$branch"
verbose $GIT worktree add ../upstream/"$branch" -B "upstream-$branch" upstream/"$branch"
else
cd ../upstream/"$branch"
if [[ $(( "$epoch" - "$($GIT log --oneline --format="%ct" HEAD -n1)" )) -gt $(( 60*60*24 )) ]]; then
verbose $GIT pull --rebase --autostash upstream "$branch" >&2
fi
fi
)
# add new upstreams
declare -a branches=()
readarray -td $'\n' branches < <( just _list_upstream_release_branches "" "" )
for branch in "${branches[@]}"; do
add_upstream "$branch"
done
# remove eol upstreams
declare -a branches=()
declare -a deleted=()
readarray -td $'\n' branches < <( just _list_eol_upstream_release_branches "" "" )
for branch in "${branches[@]}"; do
if [[ -e ../upstream/"$branch"/.git ]]; then
verbose rm -rf ../upstream/"$branch"
deleted+=("$branch")
fi
done
if [[ "${#deleted[@]}" -gt 0 ]]; then
verbose $GIT worktree prune
fi
clean:
#!/usr/bin/env -S bash -euo pipefail
cleanlist="$(just _mk_clean_list)" || exit 1
#gum choose --no-limit --height="$(($(wc -l <<<"$cleanlist") + 5))" <<<"$cleanlist" | bash -x -
gum choose --no-limit <<<"$cleanlist" | bash -x -
_mk_clean_list:
#!/usr/bin/env -S bash -euo pipefail
# set -x
(
cd master
# TODO: assert "upstream" present?
just _list_upstream_release_branches "" | xargs {{XARGS_NL}} $GIT fetch upstream
)
porcelain2jsonl() {
uniq | (
printf "["
while read key data; do
if test -z "$key"; then
printf "]\n["
else
printf '{"%s": "%s"}, ' "$key" "$data"
fi
done
echo "]"
) | sed -e 's/, ]/]/g' | grep -v '^\[\]$' | jq add -c
}
worktrees="$( cd master; git worktree list --porcelain | porcelain2jsonl )"
#cat <<<"$worktrees"
(
cd master
just _list_upstream_release_branches | xe -j0 $GIT branch --merged ||:
) | sort -u |
while IFS= read line; do
branch="$(cut <<<"$line" -c3-)"
if [[ "$branch" = "master" ]] \
|| grep <<<"$branch" "$(just _list_upstream_release_branches '^' '$')" --quiet \
|| grep <<<"$branch" "$(just _list_upstream_release_branches '^upstream-' '$')" --quiet; then
continue
fi
#jq <<<"$worktrees" '.branch'
worktree="$( jq <<<"$worktrees" 'select(.branch == "refs/heads/'"$branch"'")' -c | head -n1 )"
#echo "$line"
#echo "$branch"
#echo "$worktree"
if [[ -n "$worktree" ]]; then
path="$(jq <<<"$worktree" .worktree -r )"
if [[ -d "$path" ]]; then
if [[ "$(realpath -m --relative-to=. "$path" | cut -d/ -f1)" = "upstream" ]]; then
continue
fi
if (
cd "$path"
! $GIT diff HEAD --quiet --exit-code >&/dev/null ||
$GIT ls-files --others --exclude-standard | grep -q / # ignore toplevel dirty files
) ; then
continue
fi
if [[ "$(basename "$path")" != "tmp" ]] \
&& [[ "$(basename "$path")" != "scratch" ]]
then
printf "rm -rf %q\n" "$path"
fi
fi
fi
printf "%s\n" "( cd master && $GIT worktree prune && git branch -D \"$branch\" )"
done
#printf "%s\n" "( cd master && git worktree prune && git prune )" # slow
printf "%s\n" "( cd master && git worktree prune )"
printf "%s\n" "rmdir */ --ignore-fail-on-non-empty"
# === get/is/test ===
#get-maintainers-for-packages *attrpaths: _maintainers_tsv
get-maintainers-for-packages *attrpaths: _packages_json
#!/usr/bin/env -S bash -euo pipefail
declare -a attrpaths=("$@")
[[ "${#attrpaths[@]}" -gt 0 ]] || readarray -td $'\n' attrpaths < <( just _some_packages )
[[ "${#attrpaths[@]}" -gt 0 ]]
#grep </tmp/nixpkgs-maintainers.tsv -F "$(printf "%s\t\n" "${attrpaths[@]}")"
attrpath_json=$(printf "%s\n" "${attrpaths[@]}" | jq -sR 'split("\n")|map(select(.==""|not))' -c)
jq <packages.json --argjson attrs "$attrpath_json" '. as $pkgs | $attrs[] | $pkgs[.].meta.maintainers // [] | .[] | .github' -r | sort -u
get-versions $attrpath=`just _a_package` *paths: setup
#!/usr/bin/env -S bash -euo pipefail
declare -a paths=("${@:2}")
if [[ "${#paths[@]}" -eq 0 ]]; then
readarray -td $'\n' paths < <( just _list_upstream_release_branches "upstream/" "" )
paths=(master "${paths[@]}")
fi
just _get_version "$attrpath" "${paths[@]}" | column --table --separator ":" --output-separator " : " | bat -l conf --style=plain --paging=never
_get_version $attrpath +paths:
#!/usr/bin/env -S bash -euo pipefail
declare -a paths=("${@:2}")
for path in "${paths[@]}"; do
if [[ -d "$path" ]]; then
sleep 0.1 # HACK, sort it properly instead
echo "$attrpath.version @ $path: $(
nix eval {{NIX_EVAL_OPTS}} --file "$path"/default.nix "$attrpath" \
--apply 'let lib = import ./master/lib; in lib.getVersion' --raw
)" &
fi
done
wait
[no-cd]
test-merge $rev=`cd "$invokedir"; just _a_commit` *branches:
#!/usr/bin/env -S bash -euo pipefail
declare -a branches=("${@:2}")
[[ "${#branches[@]}" -gt 0 ]] || {
just setup # update
# readarray -td $'\n' branches < <( just _list_upstream_release_branches "upstream/" "" )
readarray -td $'\n' branches < <( prefix=upstream/ just _some_upstream_release_branches "Select targets" )
}
[[ "${#branches[@]}" -gt 0 ]] || ! echo >&2 "ERROR: no target branches chosen" || false
retval=0
for branch in "${branches[@]}"; do
echo >&2 "Checking $branch..."
if ! $GIT merge-tree "$branch" "$rev" >/dev/null; then
echo >&2 "❌ MERGE-CONFLICT with $branch"
retval=1
[[ -t 1 ]] || break # short circuit if only retcode matters
fi
done
if [[ "$retval" -eq 0 ]]; then
echo >&2 "✅ No conflicts!"
fi
exit "$retval"
[no-cd]
test-merge-in-new-branch $upstream=`just _a_upstream_release_branch "Select upstream branch"`:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "$upstream" ]] || ! echo >&2 "ERROR: No branch selected"
oldref="$(git branch --show-current ||:)"
[[ -n "$oldref" ]] || oldref="$(GIT rev-parse HEAD)"
[[ -n "$oldref" ]] || ! echo >&2 "ERROR: Unable to determine current ref"
echo >checkout-original-rev.sh "git checkout $oldref"
chmod +x checkout-original-rev.sh
remote=$(cut <<<"$upstream" -d'/' -f1)
branch=$(cut <<<"$upstream" -d'/' -f2)
set -x
git checkout -b test-merge-"$oldref"-into-"$remote"-"$branch"
git pull "$remote" "$branch" --rebase
open-package-urls $package=`just _a_package`:
#!/usr/bin/env -S bash -euo pipefail
fpkg="$(jq -rn --arg x "$package" '$x | @uri')"
bpkg="$(jq -rn --arg x "$(rev <<<"$package" | cut -d. -f1 | rev)" '$x | @uri')"
# homepage="$(nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix "$package".meta.homepage --raw ||:)"
srcpage="$(nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix "$package".src.meta.homepage --raw ||:)"
position="$({ nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix "$package".meta.position --raw ||: ; } | rev | cut -d: -f2- | rev | sd -F "$PWD/master/" "")"
declare -a urls=()
urls+=("https://hydra.nixos.org/job/nixos/trunk-combined/nixpkgs.${fpkg}.x86_64-linux")
urls+=("https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+in%3Atitle+${bpkg}")
urls+=("https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+in%3Atitle+${bpkg}")
[[ -z "$position" ]] || urls+=(https://github.com/NixOS/nixpkgs/blame/master/"$position")
[[ -z "$position" ]] || urls+=(https://github.com/NixOS/nixpkgs/commits/master/"$position")
# [[ -z "$homepage" ]] || urls+=("$homepage")
[[ -z "$srcpage" ]] || urls+=("$srcpage")
urls+=("https://search.nixos.org/packages?channel=unstable&query=${fpkg}")
printf "%s\n" "" "${urls[@]}" | fzf --reverse --multi | { grep . ||:; } | xe xdg-open
enqueue-nixpkgs-review *$prs:
#!/usr/bin/env -S bash -euo pipefail
if ! command -v pueue >/dev/null || ! pueue status >&/dev/null; then
echo >&2 "ERROR: pueue not available!"
exit 1
fi
declare -a prs=("$@")
if [[ "${#prs[@]}" -eq 0 ]]; then
readarray -td $'\n' prs < <( just _some_prs )
[[ "${#prs[@]}" -ne 0 ]]
fi
declare -a all_systems=( x86_64-linux aarch64-linux aarch64-darwin x86_64-darwin )
declare -a systems=()
readarray -td $'\n' systems < <( printf "%s\n" "${all_systems[@]}" | fzf --sync --layout=reverse --multi )
declare -a all_configs=(
''
# 'crossSystem = "aarch64-linux";' # TODO: doesn't work
# 'crossSystem = "aarch64-unknown-linux-gnu";' # TODO: doesn't work
'allowInsecurePredicate = x: true;'
'cudaSupport = true;'
'rocmSupport = true;'
# 'allowUnfree = true;' # default in nixpkgs-review
'allowUnfree = false;'
'allowBroken = true;'
# 'allowUnsupportedSystem = true;'
)
declare -a configs=()
readarray -td $'\n' "configs" < <( printf "%s\n" "${all_configs[@]}" | fzf --sync --layout=reverse --multi )
cd master # required for nixpkgs-review
prefix="$(
gum choose \
$'' \
$'bolle\t~/repos/nixpkgs/master/' \
$'eple\t~/repos/nixpkgs/master/' \
$'garp\t~/repos/nixpkgs/master/'
)"
delay_pueue=$(gum confirm "Add '--delay 15m' to pueue?" --default=yes && echo true || echo false)
gum confirm
for pr in $prs; do
declare -a cmd
# nixpkgs-review
cmd=(
nixpkgs-review pr "$pr"
--no-shell
--post-result
--systems "${systems[*]}"
)
if [[ "${#configs[@]}" -gt 0 ]]; then
cmd+=(--extra-nixpkgs-config "{ ${configs[*]} }")
fi
# TODO: --checkout commit
# TODO: --eval local
# pueue
if $delay_pueue; then
cmd=( pueue add --delay 15m --escape "${cmd[@]}" )
else
cmd=( pueue add --escape "${cmd[@]}" )
fi
# ssh
if [[ -n "$prefix" ]]; then
cmd=( ssh "$(cut <<<"$prefix" -f1)" "cd $(cut <<<"$prefix" -f2) && systemd-run --scope --user nohup $(printf " %q" "${cmd[@]}" )" )
fi
(set -x; "${cmd[@]}" )
done
# === patch helpers ===
[no-cd]
make-cargo-lock-file $attrpath=`just _a_package` $dest="":
#!/usr/bin/env -S bash -euo pipefail
cargo_path=$( nix-build . -A cargo --no-out-link )
src_unpacked=$( NIX_PATH="nixpkgs-overlays=$(realpath "{{rootdir}}/overlays.nix")" nix-build . -A ${attrpath}.src.unpacked --no-out-link )
cargo_toml=$(fzf --walker=file,hidden --walker-root "$src_unpacked/" --query Cargo.toml)
[[ -s "$cargo_toml" ]]
# ask where to put the file
if [[ -z "${dest}" && -t 0 ]]; then
attrdir=$(dirname "$(nix eval --log-format raw --file default.nix "$attrpath".meta.position --raw | cut -d: -f1 ||:)" ||:)
if [[ -n "${attrdir:-}" && -d "$attrdir" ]]; then
fd . "${attrdir}/" --type file --max-depth 1 --list-details
fi
echo "Where to put the lock file?"
dest=$(gum input --value="$(realpath --canonicalize-missing "${attrdir:-.}/Cargo.lock")")
[[ -n "$dest" ]]
[[ ! -f "$dest" ]] || gum confirm "WARNING: '$dest' exists, overwrite?"
fi
# make it
"$cargo_path"/bin/cargo generate-lockfile --manifest-path "$cargo_toml" -Z unstable-options --lockfile-path "$dest"
if [[ -t 1 ]]; then
echo "$dest"
fi
[no-cd]
make-cargo-lock-patch $attrpath=`just _a_package` $dest="":
#!/usr/bin/env -S bash -euo pipefail
cargo_path=$( nix-build . -A cargo --no-out-link )
src_unpacked=$( NIX_PATH="nixpkgs-overlays=$(realpath "{{rootdir}}/overlays.nix")" nix-build . -A ${attrpath}.src.unpacked --no-out-link )
cargo_lock=$(fzf --walker=file,hidden --walker-root "$src_unpacked/" --query Cargo.lock)
[[ -s "$cargo_lock" ]]
cargo_toml=$(sed <<<"$cargo_lock" -e "s/\.lock$/.toml/")
[[ -s "$cargo_toml" ]]
# make lock file
TMP_DIR=$(mktemp -d)
$cargo_path/bin/cargo generate-lockfile --manifest-path "$cargo_toml" -Z unstable-options --lockfile-path "$TMP_DIR/Cargo.lock"
delta "$cargo_lock" "$TMP_DIR/Cargo.lock" --paging never ||:
# ask where to put it
if [[ -z "${dest}" && -t 0 ]]; then
attrdir=$(dirname "$(nix eval --log-format raw --file default.nix "$attrpath".meta.position --raw | cut -d: -f1 ||:)" ||:)
if [[ -n "${attrdir:-}" && -d "$attrdir" ]]; then
fd . "${attrdir}/" --type file --max-depth 1 --list-details
fi
echo "Where to put the patch?"
dest=$(gum input --value="$(realpath --canonicalize-missing "${attrdir:-.}/cargo-lock.patch")")
[[ -n "$dest" ]]
[[ ! -f "$dest" ]] || gum confirm "WARNING: '$dest' exists, overwrite?"
fi
# make it
{
echo "--- a/$(realpath "$cargo_lock" | cut -d/ -f5-)"
echo "+++ b/$(realpath "$cargo_lock" | cut -d/ -f5-)"
diff --unified "$cargo_lock" "$TMP_DIR/Cargo.lock" | tail -n+3
} >"$dest" ||:
echo "$dest"
# === format helpers ===
[no-cd]
format-files-dirty:
#!/usr/bin/env -S bash -euo pipefail
git ls-files --modified | sort -u | grep . | xe -j0 nixfmt
[no-cd]
format-files-touched-by-commit *commits:
#!/usr/bin/env -S bash -euo pipefail
declare -a commits=("$@")
[[ "${#commits[@]}" -gt 0 ]] || readarray -td $'\n' commits < <( just _some_commits )
[[ "${#commits[@]}" -gt 0 ]]
printf "%s\n" "${commits[@]}" | xe -s 'git log --pretty=format: --name-only "$1"^.."$1"' | sort -u | grep . | xe nixfmt
# === internal helpers ===
[no-cd]
mk-packages-json $fname="packages.json" $rootdir=`cd "$invokedir"; git rev-parse --show-toplevel` $outpaths=`just _gum_bool "Eval outpaths?" --default=no` $system=`just _a_system` $allow_aliases=`just _gum_bool --default=no "Allow aliases?"`:
#!/usr/bin/env -S bash -euo pipefail
extra_args=()
if [[ -n "$outpaths" && "$outpaths" != false ]]; then
extra_args+=(--drv-path --out-path)
fi
# keeping this in ram requires 220mb extra memory
# TODO: use a tmpdir instead?
packages_json="$(
set -x
time nix-env </dev/null \
--extra-experimental-features no-url-literals \
--option system "$system" \
-f "$rootdir" \
-qaP \
--json \
--meta \
"${extra_args[@]}" \
--show-trace \
--no-allow-import-from-derivation \
--arg config "{ allowAliases = $allow_aliases; }" \
| sd -F "\"$(realpath "$rootdir")/" "\""
)"
cat <<<"$packages_json" >"$fname"
_packages_json:
#!/usr/bin/env -S bash -euo pipefail
{
if [[ ! -s packages.json ||
$(( "$epoch" - "$(stat -c %Y packages.json )" )) -gt $(( 60*60*24*7 ))
]]; then
set -x
[[ -d upstream/master/ ]] || just setup
if ! $GIT -C upstream/master/ diff HEAD --exit-code --quiet 1>&2; then
echo >&2 "ERROR: $(realpath upstream/master) is dirty!"
false
fi
git -C upstream/master/ pull upstream master --rebase --autostash 1>&2
just mk-packages-json "packages.json" "./upstream/master" false "$(just _this_system)" false
fi
} </dev/null # don't swallow stdin, TODO: can I do this with exec?
@_this_commit:
cd "$invokedir"; $GIT log -n1 --pretty='format:%H'
# CONCEPT:
# These getters generally have a environ JUST_{{foo}} variable which they will just print instead of doing their interactive prompt
# This allows top-level recipes to ask once and have all recursive just calls re-use the response
_a_commit *extra_revs:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_COMMIT:-}" ]] && { head -n1 <<<"$JUST_COMMIT"; exit 0; } ||:
# TODO: check if in a nixpkgs git repo
extra_args=()
[[ -z "${GIT_LOG_ALL:-}" ]] || extra_args+=(--all)
{
[[ $# -eq 0 ]] || printf "%s\n" "$@";
cd "$invokedir"; nice -n5 $GIT log --oneline "${extra_args[@]}" ||: # fails when stdout is closed early
} | fzf --reverse --header="${HEADER:-Pick commit...}" | cut -d' ' -f1 | grep .
_some_commits *extra_revs:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_COMMIT:-}" ]] && { cat <<<"$JUST_COMMIT"; exit 0; } ||:
# TODO: check if in a nixpkgs git repo
extra_args=()
[[ -z "${GIT_LOG_ALL:-}" ]] || extra_args+=(--all)
{
[[ $# -eq 0 ]] || printf "%s\n" "$@";
cd "$invokedir"; nice -n5 $GIT log --oneline "${extra_args[@]}" ||: # fails when stdout is closed early
} | fzf --reverse --header="${HEADER:-Pick commit...}" --multi | cut -d' ' -f1 | grep .
@_a_commit_title:
cd "$invokedir"; rev="$(just _a_commit)" || exit $?; [[ -n "$rev" ]] && git log --format="%s" -n1 "$rev" | grep .
_a_package: _packages_json
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_PACKAGE:-}" ]] && { head -n1 <<<"$JUST_PACKAGE"; exit 0; } ||:
#gum spin --show-output just list-packages | cut -f1 | fzf --sync --layout=reverse | grep .
just list-packages >/dev/null # HACK
just list-packages | cut -f1 | fzf --sync --layout=reverse | grep .
_some_packages: _packages_json
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_PACKAGE:-}" ]] && { cat <<<"$JUST_PACKAGE" ; exit 0; } ||:
#gum spin --show-output just list-packages | cut -f1 | fzf --sync --layout=reverse --multi | grep .
just list-packages >/dev/null
just list-packages | cut -f1 | fzf --sync --layout=reverse --multi | grep .
@_attrpaths_2_aliases:
sed -E 's/^python3[0-9]+Packages\./python3Packages./g' \
| tr '0123456789' '9876543210' | sort -u | tr '0123456789' '9876543210'
@_this_system:
nix config show system
_a_system:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_SYSTEM:-}" ]] && { head -n1 <<<"$JUST_SYSTEM"; exit 0; } ||:
# nix eval --file upstream/master/default.nix lib.systems.flakeExposed --json | jq .[] -r | xargs {{XARGS_NL}} gum choose --selected "$(just _this_system)"
systems="$(nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix lib.systems.flakeExposed --json)"
system="$(just _this_system)"
# system="aarch64-darwin"
jq <<<"$systems" .[] -r | fzf --sync --layout=reverse $(
jq <<<"$systems" --arg system "$system" -r \
'map(. == $system) | index(true) | if . == null then "" else @sh "--bind load:pos(\(. + 1))" end'
)
_some_systems:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_SYSTEM:-}" ]] && { cat -n1 <<<"$JUST_SYSTEM"; exit 0; } ||:
# nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix lib.systems.flakeExposed --json | jq .[] -r | xargs {{XARGS_NL}} gum choose --no-limit --selected "$(just _this_system)"
systems="$(nix eval {{NIX_EVAL_OPTS}} --file upstream/master/default.nix lib.systems.flakeExposed --json)"
system="$(just _this_system)"
# system="aarch64-darwin"
jq <<<"$systems" .[] -r | fzf --sync --layout=reverse --multi $(
jq <<<"$systems" --arg system "$system" -r \
'map(. == $system) | index(true) | if . == null then "" else @sh "--bind load:pos(\(. + 1))" end'
)
_a_maintainer:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_MAINTAINER:-}" ]] && { head -n1 <<<"$JUST_MAINTAINER"; exit 0; } ||:
nix eval {{NIX_EVAL_OPTS}} --file upstream/master/maintainers/maintainer-list.nix \
--apply 'x: builtins.attrValues (builtins.mapAttrs (k: v: let user = v.github or k; name = v.name or null; in [user (if name != user then name else null) (v.email or null)]) x)' --json \
| jq '.[]|@tsv' -r \
| sort --ignore-case \
| column -t -s$'\t' \
| fzf --sync --layout=reverse \
| cut -d' ' -f1
_some_maintainers:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_MAINTAINER:-}" ]] && { cat <<<"$JUST_MAINTAINER"; exit 0; } ||:
nix eval {{NIX_EVAL_OPTS}} --file upstream/master/maintainers/maintainer-list.nix \
--apply 'x: builtins.attrValues (builtins.mapAttrs (k: v: let user = v.github or k; name = v.name or null; in [user (if name != user then name else null) (v.email or null)]) x)' --json \
| jq '.[]|@tsv' -r \
| sort --ignore-case \
| column -t -s$'\t' \
| fzf --sync --layout=reverse --multi \
| cut -d' ' -f1
_a_committer: _committers_jsonl
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_COMMITTERS:-}" ]] && { head -n1 <<<"$JUST_COMMITTERS"; exit 0; } ||:
nix eval {{NIX_EVAL_OPTS}} --file upstream/master/maintainers/maintainer-list.nix \
--apply 'x: builtins.attrValues (builtins.mapAttrs (k: v: let user = v.github or k; name = v.name or null; in [user (if name != user then name else null) (v.email or null)]) x)' --json \
| jq --argjson committers "$(jq <.direnv/nixpkgs-committers.jsonl -s 'map(.login)' -c)" '.[] | .[0] as $github| select([$committers[]|.==$github]|any) | @tsv' -r \
| sort --ignore-case \
| column -t -s$'\t' \
| fzf --sync --layout=reverse \
| cut -d' ' -f1
_some_committers: _committers_jsonl
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_COMMITTERS:-}" ]] && { cat <<<"$JUST_COMMITTERS"; exit 0; } ||:
nix eval {{NIX_EVAL_OPTS}} --file upstream/master/maintainers/maintainer-list.nix \
--apply 'x: builtins.attrValues (builtins.mapAttrs (k: v: let user = v.github or k; name = v.name or null; in [user (if name != user then name else null) (v.email or null)]) x)' --json \
| jq --argjson committers "$(jq <.direnv/nixpkgs-committers.jsonl -s 'map(.login)' -c)" '.[] | .[0] as $github| select([$committers[]|.==$github]|any) | @tsv' -r \
| sort --ignore-case \
| column -t -s$'\t' \
| fzf --sync --layout=reverse --multi \
| cut -d' ' -f1
_committers_jsonl:
#!/usr/bin/env -S bash -euo pipefail
# TODO: this requires 'gh login'?
cachefile=.direnv/nixpkgs-committers.jsonl
if [[ ! -s "$cachefile" ||
$(( "$epoch" - "$(stat -c %Y "$cachefile" )" )) -gt $(( 60*60*24*7*4 ))
]]; then
[[ ! -f "${cachefile}.staging" ]] || rm -v "${cachefile}.staging"
let page=0 ||:
while
((page++))
resp="$(
gh api -H 'X-GitHub-Api-Version: 2022-11-28' "/orgs/nixos/teams/nixpkgs-committers/members?per_page=100&page=${page}" | jq '.[]' -c
)"
cat <<<"$resp" >>"${cachefile}.staging"
[[ "$(wc -l <<<"$resp" )" -ge 100 ]]
do true; done
sort <"${cachefile}.staging" -u --ignore-case > "$cachefile"
rm "${cachefile}.staging"
fi
_a_pr:
@JUST_GUM_FILTER_NO_LIMIT=0 just _some_prs
_some_prs:
#!/usr/bin/env -S bash -euo pipefail
[[ -n "${JUST_PR:-}" ]] && { cat <<<"$JUST_PR"; exit 0; } ||:
declare -a possible_args=(
"--state open"
"--author @me"
"--state closed"
"--state merged"
"--state all"
# "--search 'ASDASDASD'"
# TODO: multiple --label seems to AND...
"--label '12.approvals: 1'"
"--label '12.approvals: 2'"
"--label '12.approvals: 3+'"
"--label '12.approved-by: package-maintainer'"
"--label '11.by: package-maintainer'"
"--label '11.by: upstream-developer'"
"--label '1.severity: significant'"
"--label '1.severity: channel blocker'"
"--label '1.severity: security'"
"--label '1.severity: blocker'"
"--label '9.needs: reviewer'"
"--label '12.first-time contribution'"
"--label '2.status: stale'"
"--label '8.has: package (new)'"
"--label '8.has: package (update)'"
"--label '8.has: module (new)'"
"--label '8.has: module (update)'"
)
readarray -td $'\n' args < <(gum filter --no-limit -- "${possible_args[@]}")
cd upstream/master
declare -a gum_args=()
if [[ "${JUST_GUM_FILTER_NO_LIMIT:-1}" -ne 0 ]]; then
gum_args+=(--no-limit)
fi
(
set -x
gh pr list --limit 1000 --json 'number,title' --state open ${args[@]}
) | jq '.[]|"\(.number) - \(.title)"' -r | gum filter --placeholder "Pick PR..." --height 15 "${gum_args[@]}" | cut -d' ' -f1
@_list_upstream_release_branches $prefix="upstream/" $suffix="":
printf "${prefix//%/%%}%s${suffix//%/%%}\n" \
master staging staging-next \
python-updates \
release-25.05 staging-25.05 staging-next-25.05
@_list_eol_upstream_release_branches $prefix="upstream/" $suffix="":
printf "${prefix//%/%%}%s${suffix//%/%%}\n" \
release-24.11 staging-24.11 staging-next-24.11 \
release-24.05 staging-24.05 staging-next-24.05 \
release-23.11 staging-23.11 staging-next-23.11 \
release-23.05 staging-23.05 staging-next-23.05 \
release-22.11 staging-22.11 staging-next-22.11 \
release-22.05 staging-22.05 staging-next-22.05 \
release-21.11 staging-21.11 staging-next-21.11 \
release-21.05 staging-21.05 staging-next-21.05
@_a_upstream_release_branch $header *extra_branches:
gum filter --header="$header" "${@:2}" $(just _list_upstream_release_branches "${prefix:-upstream/}" "${suffix:-}")
# --ordered
@_some_upstream_release_branches $header *extra_branches:
gum filter --header="$header" "${@:2}" $(just _list_upstream_release_branches "${prefix:-upstream/}" "${suffix:-}") --no-limit
# --ordered
@_sanitize_pr_url $number:
echo "$number" | tr '[:upper:]' '[:lower:]' | sed -Ee 's|https?://github.com/nixos/nixpkgs/pull/([0-9]+).*|\1|'
@_a_remote_branch $remote="origin":
cd master; $GIT fetch "$remote"
cd master; $GIT for-each-ref --sort=committerdate refs/remotes --format='%(committerdate:short) %(refname:short)' | sort -r | grep " $remote/" | gum filter --height=15 --no-sort | cut -d' ' -f2-
[no-exit-message]
_gum_bool *args:
gum confirm "$@" && echo true || echo false
[no-cd]
[no-exit-message]
_enter_interactive_shell *_:
#!/usr/bin/env -S bash -euo pipefail
if [[ -t 0 && -z "${SSH_CLIENT:-}" && -z "${SSH_TTY:-}" ]]; then
# report new working dir to terminal so that tab are spawned relative
# based on ghostty:src/shell-integration/bash/ghostty.bash
if [[ -n "$GHOSTTY_RESOURCES_DIR" ]]; then
_ghostty_last_reported_cwd="$PWD"
builtin printf "\e]7;kitty-shell-cwd://%s%s\a" "$HOSTNAME" "$PWD"
fi
fi
# TODO: skip if no tty?
# TODO: -l ?
exec "$SHELL" "$@"
# TODO: somehow report the old PWD here, will require i rethink the use of [no-cd] and maybe instead accept the new working dir via an argument
# maintenance
@_fmt_justfile:
just --unstable --fmt
#sd "\n+(@_[a-zA-Z_-]+:)" "\n" justfile