Files
Oca-Repos-Manager/oca-repos-manager.sh
2024-10-22 18:49:03 +02:00

553 lines
16 KiB
Bash

#!/bin/bash
# Copyright 2024 Fabrizio Forlini <fabrizio@forlini.it>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Version: 1.0.0
set -uo pipefail
readonly orm_file="${HOME}/.oca-repos-manager/orm.conf"
readonly color_success="\e[32m"
readonly color_warning="\e[33m"
readonly color_danger="\e[31m"
readonly color_link="\e[36m"
readonly color_end="\e[0m"
readonly bold="\e[1m"
readonly bold_end="\e[0m"
update_all() {
local repos=( $(get_local_repos) )
update_oca_repos "${repos[@]}"
update_ocb
}
update_ocb() {
local exit_code
printf "\n%s\n" "Start updating OCB..."
echo "Entering: ${ocb_install_path}" >&2
cd ${ocb_install_path} && git pull
exit_code=$?
if [[ "${exit_code}" -ne 0 ]]; then
printf "${color_danger}%s${color_end},\n" "Error! Something was wrong updating OCB..."
fi
if [[ "${exit_code}" -eq 0 ]]; then
printf "\n${bold}%b${bold_end}\n" "Update complete!"
else
printf "${color_danger}%s${color_end}\n" "Error! Something was wrong during the update process."
exit 1
fi
}
show_installed_repos_path() {
local content=( $( find ${oca_addons_install_path} -mindepth 1 -maxdepth 1 -type d ) )
if [[ -z ${content[@]} ]]; then
printf "\n\n\t\t${bold}%b${bold_end}\n" "No repositories found!"
else
printf "\n\n%s\n\n" "Please, ENSURE 'addons_path' variable in your Odoo configuration file contains:"
printf "${color_success}\t%b${color_end},\n" "${content[@]}"
fi
}
get_local_repos() {
local local_repos=( $( find ${oca_addons_install_path} -mindepth 1 -maxdepth 1 -type d -exec basename {} \; ) )
echo "${local_repos[@]}"
}
select_oca_repos_to_update() {
local repos=( $(get_local_repos) )
local selected_repos
select_repos "update_oca_repos" "${repos[@]}"
}
update_oca_repos() {
local exit_code
printf "\n%s\n" "Start updating..."
for repo in $@; do
echo "Entering: ${oca_addons_install_path}/${repo}" >&2
cd ${oca_addons_install_path}/${repo} && git pull
exit_code=$?
if [[ "${exit_code}" -ne 0 ]]; then
printf "${color_danger}%s${color_end},\n" "Error! Something was wrong updating ${repo} repository..."
fi
done
if [[ "${exit_code}" -eq 0 ]]; then
printf "\n${bold}%b${bold_end}\n" "Update complete!"
else
printf "${color_danger}%s${color_end}\n" "Error! Something was wrong during the update process."
exit 1
fi
}
select_repos_to_clone() {
local repos
while true; do
if [ -z "${gh_token:-}" ]; then
set_github_token
fi
if [[ $(verify_github_token "${gh_token}") == false ]]; then
printf "\n${color_danger}%b${color_end}" "Token not valid!"
set_github_token
continue
fi
break
done
repos=( $(get_repos_names) )
select_repos "clone_repos" "${repos[@]}"
show_installed_repos_path
}
clone_repos() {
local exit_code
printf "\n%s\n" "Start cloning..."
for repo in ${@}; do
if [[ -d "${oca_addons_install_path}/${repo}" ]]; then
printf "${color_warning}%b${color_end},\n" "Repo ${repo} already exist! Skipped..."
continue
fi
cd ${oca_addons_install_path} && git clone https://github.com/OCA/${repo}.git --branch ${odoo_version} --single-branch
if [[ "${?}" -ne 0 ]]; then
printf "${color_danger}%s${color_end},\n" "Error! Something was wrong cloning ${repo} repository..."
fi
done
printf "\n${bold}%b${bold_end}\n" "Clone complete!"
}
select_repos() {
local cmd=$1
shift
local repos_names=("${@}")
local selected=()
local item
local nums=()
local num
COLUMNS=$(tput cols)
if [[ ! -z "${repos_names[@]}" ]]; then
while true; do
selected=()
nums=()
echo -e "\n"
PS3=$'\nPlease, select the repositories : (eg: "1 2 3", "1-3", repo name, or "A" for ALL)\n==> '
select _ in "${repos_names[@]}" ; do
for item in ${REPLY}; do
if [[ "${item}" =~ ^(A)+$ ]]; then
selected+=( "${repos_names[@]}" )
break
fi
if [[ "${item}" =~ ^([0-9]*)-([0-9]*)+$ ]]; then
nums+=( $( seq ${item//[!0-9]/ } ) )
fi
if [[ "${item}" =~ ^[0-9]+$ ]]; then
nums+=( ${item} )
fi
if [[ " ${repos_names[*]} " = *" ${item} "* ]]; then
selected+=( ${item} )
fi
done
for num in "${nums[@]}"; do
if [[ -n "${num}" && "${num}" -gt 0 && "${num}" -le "${#repos_names[@]}" ]]; then
selected+=(${repos_names[num - 1]})
fi
done
[[ ${#selected[@]} -gt 0 ]] && break
done
echo -e "\n"
echo "--------------------------------------------------------"
echo " SELECTED REPOS "
echo "--------------------------------------------------------"
printf "%b\n" "${selected[@]}"
echo "--------------------------------------------------------"
echo
echo "Do you want to proceed? [y/N]"
echo -n "==> "
read -sn 1
case "${REPLY}" in
Y|y)
${cmd} "${selected[@]}"
break
;;
*)
continue
;;
esac
done
else
printf "\n\n\t\t${bold}%b${bold_end}\n" "No repositories found!"
fi
}
sort_array() {
sorted=()
while IFS= read -rd '' item; do
sorted+=("$item")
done < <(printf '%s\0' "$@" | sort -z)
echo "${sorted[@]}"
}
get_repos_names() {
local repos_names
local repo_name
local branch_content
local content_is_present
local all_repos_names=( $(get_all_repos_names) )
echo -en "\nFetching OCA repositories for version ${odoo_version}..." >&2
for repo_name in "${all_repos_names[@]}"; do
echo -n "." >&2
branch_content=$(curl -s -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${gh_token}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/OCA/"${repo_name}"/contents\?ref\="${odoo_version}")
content_is_present=$(echo "${branch_content}" | jq -e 'any(arrays[]; .name | . == "README.md" or . == "LICENSE" or . == "setup" or startswith(".") | not)')
if [[ "${content_is_present}" == true ]]; then
repos_names+=("${repo_name}")
fi
done
echo >&2
echo "Found ${#all_repos_names[@]} OCA repositories!" >&2
echo "Found ${#repos_names[@]} OCA repositories for Odoo ${odoo_version}!" >&2
repos_names=( $(sort_array "${repos_names[@]}") )
echo "${repos_names[@]}"
}
get_all_repos_names() {
local page
local repos_in_the_page
local repos_names_in_the_page
local all_repos_names
local ignore_repos_list=(".github" "OCB")
printf "\n\n%b" "Fetching OCA repositories..." >&2
page=1
while true; do
echo -n "." >&2
repos_in_the_page=$(curl -s -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${gh_token}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/orgs/OCA/repos?per_page=100\&page=${page}\&sort=updated)
repos_names_in_the_page=(
$( echo "${repos_in_the_page}" | jq -r '.[].name' | while read -r name; do
for ignored_repo in "${ignore_repos_list[@]}"; do
if [[ "${name}" == "${ignored_repo}" ]]; then
continue 2
fi
done
echo "${name}";
done
)
)
if [[ "${#repos_names_in_the_page[@]}" == 0 ]]; then
break
fi
((page++))
all_repos_names+=( "${repos_names_in_the_page[@]}" )
done
echo "${all_repos_names[@]}"
}
verify_github_token() {
local token=$1
local status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${gh_token}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/user)
if [[ "${status_code}" -ne 200 ]]; then
echo false
else
echo true
fi
}
set_github_token() {
local token
printf "\n\n${bold}%b${bold_end} %b\n" "Github Personal Access Token is required." "Don't you have one?"
printf "%b ${bold}${color_link}%b${color_end}${bold_end}\n\n" "Go here and create it:" "https://github.com/settings/tokens"
echo "Please. enter your Github Personal Access Token:"
echo -n "==> "
read -e token
save_in_config_file "gh_token" "${token}"
}
set_oca_addons_install_path() {
local path_selected
while true; do
printf "\n\n%s\n" "Please, insert the OCA addons install path."
echo "[Enter for default: /opt/odoo/${odoo_version}/addons/OCA/ ]:"
echo -n "==> "
read -e path_selected
if [[ -z "${path_selected:-}" ]]; then
path_selected="/opt/odoo/${odoo_version}/addons/OCA/"
fi
if [[ ! -d "${path_selected}" ]]; then
printf "\n\n${color_danger}%s${color_end}" "Path doesn't exist! Please, insert an existing one."
continue
fi
break
done
# Remove trailing slash if present
path_selected="${path_selected%/}"
save_in_config_file "oca_addons_install_path" "${path_selected}"
}
set_ocb_install_path() {
local path_selected
while true; do
printf "\n\n%s\n" "Please, insert the OCB install path."
echo "[Enter for default: /opt/odoo/${odoo_version}/OCB/ ]:"
echo -n "==> "
read -e path_selected
if [[ -z "${path_selected:-}" ]]; then
path_selected="/opt/odoo/${odoo_version}/OCB/"
fi
if [[ ! -d "${path_selected}" ]]; then
printf "\n\n${color_danger}%s${color_end}" "Path doesn't exist! Please, insert an existing one."
continue
fi
break
done
# Remove trailing slash if present
path_selected="${path_selected%/}"
save_in_config_file "ocb_install_path" "${path_selected}"
}
set_odoo_version() {
local odoo_version_selected
while true; do
printf "\n\n%b\n" "Please, select the Odoo version of your interest."
echo "[E.g. 14 -> for Odoo v14.0, 16 -> for Odoo v16.0, etc.]:"
echo -n "==> "
read -e odoo_version_selected
[[ "${odoo_version_selected}" =~ ^[[:digit:]]+$ ]] || continue
(( ( "${odoo_version_selected}" >= 1 ) && ( "${odoo_version_selected}" <= 30 ) )) || continue
odoo_version_selected="${odoo_version_selected}.0"
save_in_config_file "odoo_version" "${odoo_version_selected}"
break
done
}
save_in_config_file() {
local key=$1
local value=$2
if ! grep -q "${key}=" "${orm_file}"; then
echo "${key}=${value}" >> ${orm_file};
get_config_file
return
fi
sed -i.bak "s:${key}.*:${key}=${value}:g" "${orm_file}"
get_config_file
}
get_config_file() {
mkdir -p $(dirname "${orm_file}")
touch "${orm_file}"
source "${orm_file}" 2>/dev/null
}
settings_menu() {
while true; do
echo
echo "********************************************************"
echo " SETTINGS "
echo "********************************************************"
printf "${bold}%s ${color_success}%b${color_end}\n" " > Odoo target version:" "${odoo_version}"
printf "${bold}%s ${color_success}%b${color_end}\n" " > OCB install path:" "${ocb_install_path}"
printf "${bold}%s ${color_success}%b${color_end}\n" " > OCA addons install path:" "${oca_addons_install_path}"
echo "********************************************************"
echo
echo "1) Change Odoo target version"
echo "2) Change OCB install path"
echo "3) Change OCA addons install path"
echo "---"
echo "4) Back"
echo
echo -n "==> "
read -sn 1
case "${REPLY}" in
1)
set_odoo_version
continue
;;
2)
set_ocb_install_path
continue
;;
3)
set_oca_addons_install_path
continue
;;
4)
main_menu
break
;;
*)
echo "Choice not valid!"
continue
;;
esac
done
}
main_menu() {
while true; do
echo
echo "********************************************************"
printf "\t\t\t${bold}%s${bold_end}\n" "MAIN MENU"
echo "********************************************************"
echo
echo "1) Clone OCA repositories"
echo "2) Show installed repositories path for Odoo config file"
echo "3) Update OCA repositories already cloned"
echo "4) Update OCB"
echo "5) Update All"
echo "---"
echo "6) Settings"
echo "---"
echo "q) Exit"
echo
echo -n "==> "
read -sn 1
case "${REPLY}" in
1)
select_repos_to_clone
read -p $'\nPress any key to continue...'
continue
;;
2)
show_installed_repos_path
read -p $'\nPress any key to continue...'
continue
;;
3)
select_oca_repos_to_update
read -p $'\nPress any key to continue...'
continue
;;
4)
update_ocb
read -p $'\nPress any key to continue...'
continue
;;
5)
update_all
read -p $'\nPress any key to continue...'
continue
;;
6)
settings_menu
continue
;;
q|Q)
exit 0
;;
*)
echo "Choice not valid!"
continue
;;
esac
done
}
check_dependencies() {
for cmd in "${@}"; do
command -v "${cmd}" > /dev/null
local exitcode=$?
if [[ "${exitcode}" -ne "0" ]]; then
echo -e "\n${cmd} is missing. Please, install it. E.g.: apt install ${cmd}"
echo -e "\nQuitting..."
exit "${exitcode}"
fi
done
}
intro_banner() {
echo
echo
echo " ╔═╗╔═╗╔═╗ "
echo " ║ ║║ ╠═╣ "
echo " ╚═╝╚═╝╩ ╩ "
echo " ┬─┐┌─┐┌─┐┌─┐┌─┐ ┌┬┐┌─┐┌┐┌┌─┐┌─┐┌─┐┬─┐ "
echo " ├┬┘├┤ ├─┘│ │└─┐ │││├─┤│││├─┤│ ┬├┤ ├┬┘ "
echo " ┴└─└─┘┴ └─┘└─┘ ┴ ┴┴ ┴┘└┘┴ ┴└─┘└─┘┴└─ "
echo
}
main() {
intro_banner
check_dependencies jq curl git
get_config_file
if [[ -z "${odoo_version+x:-}" ]]; then
set_odoo_version
fi
if [[ -z "${ocb_install_path+x:-}" ]]; then
set_ocb_install_path
fi
if [[ -z "${oca_addons_install_path+x:-}" ]]; then
set_oca_addons_install_path
fi
main_menu
}
main