#!/bin/bash
# compare the pip freeze output of two python venv directories
# by convention the venv is in the .venv subpath
# WF 2025-01-24
# global settings
debug=false
# ANSI color codes
blue='\033[0;34m'
red='\033[0;31m'
green='\033[0;32m'
endColor='\033[0m'
#
# Display a colored message
# params:
# 1: l_color - the color of the message
# 2: l_msg - the message to display
#
color_msg() {
local l_color="$1"
local l_msg="$2"
echo -e "${l_color}${l_msg}${endColor}"
}
#
# Display an error message and exit
# params:
# 1: l_msg - the error message to display
#
error() {
local l_msg="$1"
color_msg $red "Error:"
color_msg $red "\t$l_msg"
exit 1
}
#
# Display usage information
#
usage() {
color_msg $blue "Usage: $0 [-d|--debug] --diff "
color_msg $green "
Options:
--debug Enable debug mode to print the sorted package lists from each virtual environment.
--diff Compare two virtual environments by analyzing their 'pip freeze' outputs.
Path to the first virtual environment.
Path to the second virtual environment.
"
exit 1
}
#
# Extract packages from a virtual environment
# params:
# 1: l_path - Path to the virtual environment
# 2: l_output - File to store the package list
# 3: debug - show debug output
#
get_packages() {
local l_path="$1/.venv"
local l_output="$2"
local l_debug="$3"
if [ ! -d "$l_path" ]; then
error "Path '$l_path' does not exist or is not a directory."
fi
if [ ! -f "$l_path/bin/activate" ]; then
error "Path '$l_path' is not a valid virtual environment."
fi
source "$l_path/bin/activate" || error "Failed to activate virtual environment at '$l_path'."
pip freeze | LC_ALL=C sort -k 1b,1 > "$l_output"
if $l_debug; then
color_msg $green "Debug: Sorted packages from $l_path written to $l_output"
cat "$l_output"
fi
deactivate
}
#
# Compare packages between two environments and print results
# params:
# 1: l_venv1_packages - File containing packages from venv1
# 2: l_venv2_packages - File containing packages from venv2
#
compare_packages() {
local l_venv1_packages="$1"
local l_venv2_packages="$2"
# Packages only in venv1
color_msg $blue "Packages only in the first virtual environment:"
comm -23 "$l_venv1_packages" "$l_venv2_packages" || error "Failed to compare packages."
# Packages only in venv2
echo
color_msg $blue "Packages only in the second virtual environment:"
comm -13 "$l_venv1_packages" "$l_venv2_packages" || error "Failed to compare packages."
# Common packages with version differences
echo
color_msg $blue "Common packages with version differences:"
join -t= -j1 "$l_venv1_packages" "$l_venv2_packages" | awk -F= '
NR==FNR {a[$1]=$0; next}
($1 in a) && ($0 != a[$1]) {print $0, "vs", a[$1]}
' "$l_venv1_packages" "$l_venv2_packages"
}
# compare
# the pip freeze output of two python venv directories
# Paths to the virtual environments
compare() {
local VENV1="$1"
local VENV2="$2"
local l_debug="$3"
# Temporary files for package lists
local VENV1_PACKAGES=$(mktemp)
local VENV2_PACKAGES=$(mktemp)
# Extract packages from both virtual environments
get_packages "$VENV1" "$VENV1_PACKAGES" "$l_debug"
get_packages "$VENV2" "$VENV2_PACKAGES" "$l_debug"
# Compare the package lists
compare_packages "$VENV1_PACKAGES" "$VENV2_PACKAGES"
# Clean up temporary files
rm -f "$VENV1_PACKAGES" "$VENV2_PACKAGES"
}
# Check for correct number of arguments
while [ "$1" != "" ]
do
option="$1"
case $option in
"-d"|"--debug")
color_msg $blue "setting debug mode ..."
debug=true
;;
"-h"|"--help")
usage
;;
"--diff")
shift
if [ "$#" -ne 2 ]; then
usage
else
compare "$1" "$2" "$debug"
# shift 1 here one will be in the main loop
shift
fi
esac
shift
done
venvdiff --diff source/python/nicescad source/python/nicepdf/
Packages only in the first virtual environment:
Jinja2==3.1.4
aiohappyeyeballs==2.4.3
aiohttp==3.10.8
bcrypt==4.1.2
certifi==2024.7.4
colour==0.1.5
dataclasses-json==0.6.4
marshmallow==3.20.2
ngwidgets==0.19.1
nicegui==2.2.0
nicescad @ file:///home/wf/source/python/nicescad
openai==1.12.0
orjson==3.10.7
packaging==23.2
ply==3.11
requests==2.32.3
shutup==0.2.0
solidpython2==2.0.3
urllib3==2.2.2
yarl==1.13.1
Packages only in the second virtual environment:
Jinja2==3.1.3
Pillow==10.1.0
aiohttp==3.9.5
bcrypt==4.0.1
certifi==2023.7.22
dataclasses-json==0.6.5
marshmallow==3.21.1
ngwidgets==0.14.2
nicegui==1.4.23
nicepdf @ file:///home/wf/source/python/nicepdf
openai==1.24.0
orjson==3.10.1
packaging==24.0
pypdf==3.17.4
reportlab==4.0.6
requests==2.31.0
urllib3==2.1.0
yarl==1.9.2
Common packages with version differences:
join: /tmp/tmp.nLYH1ZfkhW:32: is not sorted: fastapi==0.109.2
join: /tmp/tmp.2u3q1j2krR:31: is not sorted: fastapi==0.109.2
join: input is not in sorted order
Jinja2==3.1.3 vs Jinja2==3.1.4
aiohttp==3.9.5 vs aiohttp==3.10.8
bcrypt==4.0.1 vs bcrypt==4.1.2
certifi==2023.7.22 vs certifi==2024.7.4
dataclasses-json==0.6.5 vs dataclasses-json==0.6.4
marshmallow==3.21.1 vs marshmallow==3.20.2
ngwidgets==0.14.2 vs ngwidgets==0.19.1
nicegui==1.4.23 vs nicegui==2.2.0
openai==1.24.0 vs openai==1.12.0
orjson==3.10.1 vs orjson==3.10.7
packaging==24.0 vs packaging==23.2
requests==2.31.0 vs requests==2.32.3
urllib3==2.1.0 vs urllib3==2.2.2
yarl==1.9.2 vs yarl==1.13.1
будет ли лучше/стандартное решение для этого? Join дает предупреждение «файл не в отсортированном порядке»
Два из моих питонов ведут ведут себя по -разному, и это кажется тонким изменением зависимостей ПИП. /p> [code]#!/bin/bash # compare the pip freeze output of two python venv directories # by convention the venv is in the .venv subpath # WF 2025-01-24
# global settings debug=false
# ANSI color codes blue='\033[0;34m' red='\033[0;31m' green='\033[0;32m' endColor='\033[0m'
# # Display a colored message # params: # 1: l_color - the color of the message # 2: l_msg - the message to display # color_msg() { local l_color="$1" local l_msg="$2" echo -e "${l_color}${l_msg}${endColor}" }
# # Display an error message and exit # params: # 1: l_msg - the error message to display # error() { local l_msg="$1" color_msg $red "Error:" color_msg $red "\t$l_msg" exit 1 }
# # Display usage information # usage() { color_msg $blue "Usage: $0 [-d|--debug] --diff " color_msg $green " Options: --debug Enable debug mode to print the sorted package lists from each virtual environment. --diff Compare two virtual environments by analyzing their 'pip freeze' outputs. Path to the first virtual environment. Path to the second virtual environment. " exit 1 }
# # Extract packages from a virtual environment # params: # 1: l_path - Path to the virtual environment # 2: l_output - File to store the package list # 3: debug - show debug output # get_packages() { local l_path="$1/.venv" local l_output="$2" local l_debug="$3" if [ ! -d "$l_path" ]; then error "Path '$l_path' does not exist or is not a directory." fi if [ ! -f "$l_path/bin/activate" ]; then error "Path '$l_path' is not a valid virtual environment." fi source "$l_path/bin/activate" || error "Failed to activate virtual environment at '$l_path'." pip freeze | LC_ALL=C sort -k 1b,1 > "$l_output" if $l_debug; then color_msg $green "Debug: Sorted packages from $l_path written to $l_output" cat "$l_output" fi deactivate }
# # Compare packages between two environments and print results # params: # 1: l_venv1_packages - File containing packages from venv1 # 2: l_venv2_packages - File containing packages from venv2 # compare_packages() { local l_venv1_packages="$1" local l_venv2_packages="$2"
# Packages only in venv1 color_msg $blue "Packages only in the first virtual environment:" comm -23 "$l_venv1_packages" "$l_venv2_packages" || error "Failed to compare packages."
# Packages only in venv2 echo color_msg $blue "Packages only in the second virtual environment:" comm -13 "$l_venv1_packages" "$l_venv2_packages" || error "Failed to compare packages."
# Common packages with version differences echo color_msg $blue "Common packages with version differences:" join -t= -j1 "$l_venv1_packages" "$l_venv2_packages" | awk -F= ' NR==FNR {a[$1]=$0; next} ($1 in a) && ($0 != a[$1]) {print $0, "vs", a[$1]} ' "$l_venv1_packages" "$l_venv2_packages" }
# compare # the pip freeze output of two python venv directories # Paths to the virtual environments compare() { local VENV1="$1" local VENV2="$2" local l_debug="$3"
# Temporary files for package lists local VENV1_PACKAGES=$(mktemp) local VENV2_PACKAGES=$(mktemp)
# Extract packages from both virtual environments get_packages "$VENV1" "$VENV1_PACKAGES" "$l_debug" get_packages "$VENV2" "$VENV2_PACKAGES" "$l_debug"
# Compare the package lists compare_packages "$VENV1_PACKAGES" "$VENV2_PACKAGES"
# Clean up temporary files rm -f "$VENV1_PACKAGES" "$VENV2_PACKAGES" }
# Check for correct number of arguments while [ "$1" != "" ] do option="$1" case $option in "-d"|"--debug") color_msg $blue "setting debug mode ..." debug=true ;; "-h"|"--help") usage ;; "--diff") shift if [ "$#" -ne 2 ]; then usage else compare "$1" "$2" "$debug" # shift 1 here one will be in the main loop shift fi esac shift done [/code] [b]Пример вызова:[/b] [code]venvdiff --diff source/python/nicescad source/python/nicepdf/ Packages only in the first virtual environment: Jinja2==3.1.4 aiohappyeyeballs==2.4.3 aiohttp==3.10.8 bcrypt==4.1.2 certifi==2024.7.4 colour==0.1.5 dataclasses-json==0.6.4 marshmallow==3.20.2 ngwidgets==0.19.1 nicegui==2.2.0 nicescad @ file:///home/wf/source/python/nicescad openai==1.12.0 orjson==3.10.7 packaging==23.2 ply==3.11 requests==2.32.3 shutup==0.2.0 solidpython2==2.0.3 urllib3==2.2.2 yarl==1.13.1
Packages only in the second virtual environment: Jinja2==3.1.3 Pillow==10.1.0 aiohttp==3.9.5 bcrypt==4.0.1 certifi==2023.7.22 dataclasses-json==0.6.5 marshmallow==3.21.1 ngwidgets==0.14.2 nicegui==1.4.23 nicepdf @ file:///home/wf/source/python/nicepdf openai==1.24.0 orjson==3.10.1 packaging==24.0 pypdf==3.17.4 reportlab==4.0.6 requests==2.31.0 urllib3==2.1.0 yarl==1.9.2
Common packages with version differences: join: /tmp/tmp.nLYH1ZfkhW:32: is not sorted: fastapi==0.109.2 join: /tmp/tmp.2u3q1j2krR:31: is not sorted: fastapi==0.109.2 join: input is not in sorted order Jinja2==3.1.3 vs Jinja2==3.1.4 aiohttp==3.9.5 vs aiohttp==3.10.8 bcrypt==4.0.1 vs bcrypt==4.1.2 certifi==2023.7.22 vs certifi==2024.7.4 dataclasses-json==0.6.5 vs dataclasses-json==0.6.4 marshmallow==3.21.1 vs marshmallow==3.20.2 ngwidgets==0.14.2 vs ngwidgets==0.19.1 nicegui==1.4.23 vs nicegui==2.2.0 openai==1.24.0 vs openai==1.12.0 orjson==3.10.1 vs orjson==3.10.7 packaging==24.0 vs packaging==23.2 requests==2.31.0 vs requests==2.32.3 urllib3==2.1.0 vs urllib3==2.2.2 yarl==1.9.2 vs yarl==1.13.1 [/code] будет ли лучше/стандартное решение для этого? Join дает предупреждение «файл не в отсортированном порядке»