@@ -50,12 +50,23 @@ update_lists_helper() {
5050update_lists () {
5151 local ppa=${1:- }
5252 local ppa_search=${2:- }
53+ local status_token=${3:- $ppa_search }
5354 local list=
54- status_file=/tmp/os_lists
55+ local status_file=/tmp/os_lists
56+ local hash_cmd
5557 if [[ -n " $ppa " && -n " $ppa_search " ]]; then
56- list=" $list_dir " /" $( basename " $( grep -lr " $ppa_search " " $list_dir " ) " ) "
57- status_file=/tmp/" $( echo -n " $ppa_search " | shasum -a 256 | cut -d ' ' -f 1) "
58- elif [ -e " $list_file " ] && grep -Eq ' ^deb |^Types deb' " $list_file " ; then
58+ if [ -f " $ppa_search " ]; then
59+ list=" $ppa_search "
60+ else
61+ list=" $( grep -Elr " $ppa_search " " $list_dir " 2> /dev/null | head -n 1) "
62+ fi
63+ hash_cmd=" $( command -v sha256sum || command -v shasum) "
64+ if [ -n " $status_token " ] && [ -n " $hash_cmd " ]; then
65+ status_file=/tmp/os_lists_" $( echo -n " $status_token " | $hash_cmd | awk ' {print $1}' ) "
66+ elif [ -n " $status_token " ]; then
67+ status_file=/tmp/os_lists_$( date +%s)
68+ fi
69+ elif [ -e " $list_file " ] && grep -Eq ' ^deb |^Types: *deb' " $list_file " ; then
5970 list=" $list_file "
6071 fi
6172 if [ ! -e " $status_file " ]; then
@@ -64,6 +75,67 @@ update_lists() {
6475 fi
6576}
6677
78+ # Determine whether deb822 sources are the default on this system.
79+ get_sources_format () {
80+ if [ -n " $sources_format " ]; then
81+ echo " $sources_format "
82+ return
83+ fi
84+ sources_format=deb
85+ if [ -e " $list_dir " /ubuntu.sources ] || [ -e " $list_dir " /debian.sources ]; then
86+ sources_format=" deb822"
87+ elif ! [[ " $ID " =~ ubuntu| debian ]]; then
88+ find " $list_dir " -type f -name ' *.sources' | grep -q . && sources_format=" deb822"
89+ fi
90+ echo " $sources_format "
91+ }
92+
93+ escape_regex () {
94+ printf ' %s' " $1 " | sed -e ' s/[][\.^$*+?{}()|\/]/\\&/g'
95+ }
96+
97+ merge_components () {
98+ local out=() t
99+ for t in $1 $2 ; do [[ $t && " ${out[*]} " != * " $t " * ]] && out+=(" $t " ); done
100+ printf ' %s\n' " ${out[*]} "
101+ }
102+
103+ merge_components_from_file () {
104+ local path=$1
105+ local incoming=$2
106+ local current=
107+ if [ -n " $path " ] && [ -e " $path " ]; then
108+ current=" $( grep -E ' ^Components:' " $path " | head -n 1 | cut -d ' :' -f 2 | xargs) "
109+ fi
110+ local merged
111+ merged=" $( merge_components " $current " " $incoming " ) "
112+ if [ -z " $merged " ] || [ " $merged " = " $current " ]; then
113+ return 1
114+ fi
115+ printf ' %s\n' " $merged "
116+ }
117+
118+ # Function to get repo patterns based on format.
119+ get_repo_patterns () {
120+ local list_format=$1
121+ local ppa_url=$2
122+ local package_dist=$3
123+ local branches=$4
124+ local escaped_url
125+ local escaped_dist
126+ local escaped_branches
127+ escaped_url=" $( escape_regex " $ppa_url " ) "
128+ escaped_dist=" $( escape_regex " $package_dist " ) "
129+ escaped_branches=" $( escape_regex " $branches " ) "
130+ local deb_pattern=" ^deb .*${escaped_url} ${escaped_dist} .*${escaped_branches} $"
131+ local deb822_pattern=" ^URIs: ${escaped_url} $"
132+ if [ " $list_format " = " deb822" ]; then
133+ printf ' %s|%s\n' " $deb822_pattern " " $deb_pattern "
134+ else
135+ printf ' %s|%s\n' " $deb_pattern " " $deb822_pattern "
136+ fi
137+ }
138+
67139# Function to get fingerprint from an Ubuntu PPA.
68140ubuntu_fingerprint () {
69141 ppa=" $1 "
@@ -104,19 +176,78 @@ add_key() {
104176 fi
105177}
106178
179+ handle_existing_list () {
180+ local ppa=$1
181+ local list_format=$2
182+ branches=$3
183+ [[ " $list_format " = " deb822" && -n " $check_lists_file " ]] || {
184+ echo " Repository $ppa ($branches ) already exists"
185+ return 1
186+ }
187+ [[ " $check_lists_file " = * .list ]] && {
188+ sudo rm -f " $check_lists_file "
189+ return 0
190+ }
191+ local merged_components
192+ merged_components=" $( merge_components_from_file " $check_lists_file " " $branches " ) " && {
193+ sudo rm -f " $check_lists_file "
194+ branches=" $merged_components "
195+ return 0
196+ }
197+ echo " Repository $ppa ($branches ) already exists"
198+ return 1
199+ }
200+
201+ # Function to write a list file.
202+ write_list () {
203+ local type=$1
204+ local ppa=$2
205+ local url=$3
206+ local suite=$4
207+ local components=$5
208+ local key_file=$6
209+ local list_basename=" ${ppa%%/* } " -" $ID " -" ${ppa#*/ } " -" $suite "
210+ local arch
211+ arch=" $( dpkg --print-architecture) "
212+ sudo rm -f " $list_dir " /" ${ppa/ \/ / -} " .list " $list_dir " /" ${ppa/ \/ / -} " .sources " $list_dir " /" $list_basename " .list " $list_dir " /" $list_basename " .sources || true
213+ if [ " $type " = " deb822" ]; then
214+ cat << EOF | sudo tee "$list_dir "/"$list_basename ".sources >/dev/null
215+ Types: deb
216+ URIs: $url
217+ Suites: $suite
218+ Components: $components
219+ Architectures: $arch
220+ Signed-By: $key_file
221+ EOF
222+ else
223+ echo " deb [arch=$arch signed-by=$key_file ] $url $suite $components " | sudo tee " $list_dir " /" $list_basename " .list > /dev/null 2>&1
224+ fi
225+ }
226+
107227# Function to check if a PPA and its lists exist
108228check_lists () {
109- ppa=$1
110- ppa_search=$2
111- if grep -Eqr " $ppa_search " " $list_dir " ; then
229+ local ppa=$1
230+ local primary=${2:- }
231+ local secondary=${3:- }
232+ local status_token=${4:- $primary }
233+ local match_file=
234+ check_lists_file=
235+ if [ -n " $primary " ]; then
236+ match_file=$( grep -Elr " $primary " " $list_dir " 2> /dev/null | head -n 1)
237+ fi
238+ if [ -z " $match_file " ] && [ -n " $secondary " ]; then
239+ match_file=$( grep -Elr " $secondary " " $list_dir " 2> /dev/null | head -n 1)
240+ fi
241+ if [ -n " $match_file " ]; then
242+ local list_count
112243 list_count=" $( sudo find /var/lib/apt/lists -type f -name " *${ppa/ \/ / _} *" | wc -l) "
113244 if [ " $list_count " = " 0" ]; then
114- update_lists " $ppa " " $ppa_search "
245+ update_lists " $ppa " " $match_file " " $status_token "
115246 fi
116- return 0;
117- else
118- return 1;
247+ check_lists_file=" $match_file "
248+ return 0
119249 fi
250+ return 1
120251}
121252
122253# Function to add a sources list.
@@ -126,19 +257,24 @@ add_list() {
126257 key_source=${3:- " $ppa_url " }
127258 package_dist=${4:- " $VERSION_CODENAME " }
128259 branches=${5:- main}
129- ppa_search= " deb .* $ppa_url $package_dist .* $branches $ "
130- if check_lists " $ppa " " $ppa_search " ; then
131- echo " Repository $ppa already exists " ;
132- return 1 ;
133- else
134- arch= $( dpkg --print-architecture )
135- [ -e " $key_source " ] && key_file= $key_source || key_file= " $key_dir " / " ${ppa / \/ / -} " -keyring.gpg
136- add_key " $ppa " " $ppa_url " " $package_dist " " $key_source " " $key_file "
137- sudo rm -rf " $list_dir " / " ${ppa / \/ / -} " .list || true
138- echo " deb [arch= $arch signed-by= $key_file ] $ppa_url $package_dist $branches " | sudo tee -a " $list_dir " / " ${ppa %%/* } " - " $ID " - " ${ppa #*/ } " - " $package_dist " .list > /dev/null 2>&1
139- update_lists " $ppa " " $ppa_search "
140- . /etc/os-release
260+ local list_format
261+ list_format= " $( get_sources_format ) "
262+ local status_token
263+ status_token= " ${ppa_url} | ${package_dist} | ${branches} "
264+ local list_path=
265+ IFS= ' | ' read -r primary_pattern secondary_pattern <<< " $(get_repo_patterns " $list_format " " $ppa_url " " $package_dist " " $branches " ) "
266+ if check_lists " $ppa " " $primary_pattern " " $secondary_pattern " " $status_token " ; then
267+ list_path= " $check_lists_file "
268+ handle_existing_list " $ppa " " $list_format " " $branches " || return 1 ;
269+ check_lists_file=
270+ IFS= ' | ' read -r primary_pattern secondary_pattern <<< " $(get_repo_patterns " $list_format " " $ppa_url " " $package_dist " " $branches " ) "
271+ status_token= " ${ppa_url} | ${package_dist} | ${branches} "
141272 fi
273+ [ -e " $key_source " ] && key_file=$key_source || key_file=" $key_dir " /" ${ppa/ \/ / -} " -keyring.gpg
274+ add_key " $ppa " " $ppa_url " " $package_dist " " $key_source " " $key_file "
275+ write_list " $list_format " " $ppa " " $ppa_url " " $package_dist " " $branches " " $key_file "
276+ update_lists " $ppa " " $primary_pattern " " $status_token "
277+ . /etc/os-release
142278 return 0;
143279}
144280
@@ -148,8 +284,12 @@ check_ppa() {
148284 ppa_url=${2:- " $lpc_ppa /$ppa /ubuntu" }
149285 package_dist=${3:- " $VERSION_CODENAME " }
150286 branches=${4:- main}
151- ppa_search=" deb .*$ppa_url $package_dist .*$branches $"
152- if check_lists " $ppa " " $ppa_search " ; then
287+ local list_format
288+ list_format=" $( get_sources_format) "
289+ IFS=' |' read -r primary_pattern secondary_pattern <<< " $(get_repo_patterns " $list_format " " $ppa_url " " $package_dist " " $branches " )"
290+ local status_token
291+ status_token=" ${ppa_url} |${package_dist} |${branches} "
292+ if check_lists " $ppa " " $primary_pattern " " $secondary_pattern " " $status_token " ; then
153293 return 0;
154294 else
155295 return 1;
@@ -163,7 +303,7 @@ remove_list() {
163303 for ppa_url in " ${ppa_urls[@]} " ; do
164304 grep -lr " $ppa_url " " $list_dir " | xargs -n1 sudo rm -f
165305 done
166- sudo rm -f " $key_dir " /" ${ppa/ \/ / -} " -keyring || true
306+ sudo rm -f " $key_dir " /" ${ppa/ \/ / -} " -keyring /tmp/os_lists * || true
167307}
168308
169309# Function to check if ubuntu ppa is up
@@ -213,12 +353,23 @@ update_ppa() {
213353 ppa_url=${2:- " $lpc_ppa /$ppa /ubuntu" }
214354 package_dist=${4:- " $VERSION_CODENAME " }
215355 branches=${5:- main}
216- ppa_search=" deb .*$ppa_url $package_dist .*$branches "
217- update_lists " $ppa " " $ppa_search "
356+ local list_format
357+ list_format=" $( get_sources_format) "
358+ IFS=' |' read -r primary_pattern secondary_pattern <<< " $(get_repo_patterns " $list_format " " $ppa_url " " $package_dist " " $branches " )"
359+ local list_path
360+ list_path=" $( grep -Elr " $primary_pattern " " $list_dir " 2> /dev/null | head -n 1) "
361+ if [ -z " $list_path " ] && [ -n " $secondary_pattern " ]; then
362+ list_path=" $( grep -Elr " $secondary_pattern " " $list_dir " 2> /dev/null | head -n 1) "
363+ fi
364+ local status_token
365+ status_token=" ${ppa_url} |${package_dist} |${branches} "
366+ update_lists " $ppa " " ${list_path:- $primary_pattern } " " $status_token "
218367 . /etc/os-release
219368}
220369
221370# Variables
371+ sources_format=
372+ check_lists_file=
222373list_dir=' /etc/apt/sources.list.d'
223374list_file=" /etc/apt/sources.list.d/$ID .sources"
224375[ -e " $list_file " ] || list_file=' /etc/apt/sources.list'
0 commit comments