Use "extrepo" to add 3rd party repositories

As mentioned in another post:
When researching the apt error connected librewolf I stumbled across this command:

For me this was the first time I encountered the command "extrepo"
It is a command to add 3rd party repositories that are curated by debian

You can use "extrepo" to add over 190 different repositories
This includes also the most used ones like for instance

Brave
Librewolf
WineHQ
vscode
google_cloud
speedtest-cli
proxmox
openvpn

and many many more.

See if you can use this "extrepo" command before considering manually adding a repository because it is a more secure way to add repositories.

This because adding repository keys is the most vulnerable step securitywise.
"extrepo" makes adding the repository keys less of a trust issue because they are added to your system by the extrepo command which implies that the keys and the repositories were checked first by debian.

10 Likes

See Question #819386 “Official Ubuntu support” : Questions : extrepo package : Ubuntu

3 Likes

Hi, @stokito and welcome to the Ubuntu MATE Community!

1 Like

Does anyone know how to get extrepo to report all the "foreign" or "non-Distro" repositories that have been "configured" or "templated" to work with the extrepo facility?

I am looking for something like a "rolodex" of Apps available via that mechanism.

:slight_smile:

1 Like

extrepo search without any further arguments will give a complete listing of the foreign repositories. :slight_smile:

5 Likes

Thank you, Thom! That worked. I was under the wrong impression that you had to search for specific strings, and the man page did not state that an empty search would offer such a list.


Sample of details for any given "repository":

Found sury_apache2:
---
description: Ondřej Surý's package repository
gpg-key-checksum:
  sha256: 59961c0e0d9c9415c2a6b8cf7355bc48254ab53c7e1b8211b683eb459353da81
gpg-key-file: sury_apache2.asc
policy: main
source:
  Architectures: amd64 armhf arm64
  Components: main
  Suites: bookworm
  Types: deb deb-src
  URIs: https://packages.sury.org/apache2

extrepo search | grep '^Found' | sort | sed 's+^Found ++'  | sed 's+[:]$++'

Count of items identified: 300

1password
45drives
angie
antigravity
anydesk
apertium-nightly
apertium-release
arctic-project
armbian
azure-cli
bareos
beagleboard-arm64
beagleboard-armhf
belgium_beidconnect
belgium_eid
belgium_eid_continuous
bird2
bird3
brave_beta
brave_nightly
brave_release
caddyserver
ceph
ceph_reef
ceph-tentacle
consol
cozy
crowdsec
ddev
debian_backports
debian_backports_sloppy
debian_official
debian-rocm
deb-multimedia
deb-multimedia-backports
dnsdist-19
dnsdist-20
dnsdist-21
dnsdist-master
dns-oarc
dns-oarc-prerelease
docker-ce
dotnet
dovecot
edge
elastic
elastic_7
elastic_8
elastic_9
elbe
element.io
eturnal
fai
fasttrack_backports
ferron
firefoxpwa
foreman-3.12
foreman-3.13
foreman-3.14
foreman-nightly
foreman-plugins-3.12
foreman-plugins-3.13
foreman-plugins-3.14
foreman-plugins-nightly
github-cli
gitlab_ce
gitlab_ee
gitlab_runner
google_chrome
google_cloud
gopasspw
grafana
grafana_beta
grafana_enterprise
grafana_enterprise_beta
haproxy-2.6
haproxy-2.8
haproxy-3.0
haproxy-3.1
haproxy-3.2
hashicorp
helm
holland
hwraid
i2pd
influxdb
jellyfin
jenkins
jenkins-lts
jitsi-stable
joplin
josm
kamailio-5.8
kamailio-5.8-nightly
kamailio-6.0
kamailio-6.0-nightly
kamailio-dev-nightly
kea
kea-3-0
keybase
khumba
kicksecure
kicksecure_developers
kicksecure_proposed
kicksecure_testers
knot-dns
knot-resolver
kubernetes
kubernetes-1.24
kubernetes-1.25
kubernetes-1.26
kubernetes-1.27
kubernetes-1.28
kubernetes-1.29
kubernetes-1.30
kubernetes-1.31
kubernetes-1.32
kubernetes-1.33
kubernetes-1.34
kubernetes-1.35
libmongocrypt-1.13
libmongocrypt-1.14
libmongocrypt-development
librewolf
lihas
linux-libre-freesh
liquorix
mariadb-10.11
mariadb-11.4
mariadb-11.8
mariadb-12
mariadb-tools
matrix
mattermost
maxscale
meshtastic
mise
mobian
mongodb
mozilla
mullvad
mullvad-beta
mullvad-stable
mysql
mysql-8.0
mysql-8.4
mysql-lts
neurodebian_software
newrelic
nginx
nlnetlabs
nlnetlabs-proposed
node_18.x
node_20.x
node_22.x
node_23.x
node_24.x
node_25.x
notesalexp
nushell
nvidia-cuda
nvidia-cuda-sbsa
nvidia-docker
n.wtf
onlyoffice-desktopeditors
ooni
openbao
openitcockpit
openmediavault
openmediavault-proposed
openmodelica-contrib-nightly
openmodelica-contrib-release
openmodelica-contrib-stable
openmodelica-nightly
openmodelica-release
openmodelica-stable
opennebula
openstack_antelope
openstack_bobcat
openstack_caracal
openstack_dalmatian
openstack_epoxy
openstack_zed
opentofu
openvpn
openxpki
opera_stable
opsi
osmocom-latest
osmocom-nightly
passbolt
percona-release
pgadmin
postgresql
powerdns-auth-48
powerdns-auth-49
powerdns-auth-50
powerdns-auth-master
powerdns-rec-50
powerdns-rec-51
powerdns-rec-52
powerdns-rec-53
powerdns-rec-54
powerdns-rec-master
prosody
proxmox-ceph-quincy
proxmox-ceph-reef
proxmox-ceph-squid
proxmox-pbs
proxmox-pbs-client
proxmox-pmg
proxmox-pve
proxmox-pve8
puppet
puppet8
pyxian
raspberrypi
realsense
redis
reform.debian.net
resilio-sync
r-project
rspamd
sapmachine
satnogs
signal
slack
speedtest-cli
spotify
steam
sublime_dev
sublime_stable
surface-linux
sury
sury_apache2
sury_bind
sury_bind-dev
sury_bind-esv
sury_nginx
sury_nginx-mainline
syncevolution
syncthing
t2linux
tailscale
teams-for-linux
teamviewer_default
teamviewer_preview
teleport
temurin
termius
ti-debpkgs
torproject
trinity
trinity-testing
trivy
turnkeylinux
turnkeylinux-security
turnkeylinux-testing
tuxlava
tuxmake
tuxrun
tuxsuite
unifi
uv
varnish60lts
varnish76
varnish77
varnish80
vector
vector_0.x
virtualbox
vscode
vscodium
waydroid
webmin
weechat
whonix
whonix_developers
whonix_proposed
whonix_testers
windsurf
winehq
wire-desktop
wire-internal-desktop
wtf
wtf-lts
x2go
x2go-extras
x2go-lts
x2go-nightly
xanmod
xcaddy
xlibre
xpra
xpra-beta
xtom
yarnpkg
zammad
zotero
zulu-openjdk
3 Likes

That is one beautiful oneliner for a sorted 'repo index'. Kudos ! :+1:

3 Likes

If you liked that, you might like this one.

Utility to report only the entries related to the selected Architecture.

#!/bin/sh

selectArch()
{
	choice=$(yad --list --title "ACTION - Choose Architecture" \
	--text "Double-Click on your selection:\n" \
	--width=800 \
	--height=450 \
	--column "Options" \
	${hostArch} ${archOptions} \
	--no-headers | sed 's+[|]$++' )
}

	########################################################################
	########################################################################

hostArch=$( dpkg-architecture -q DEB_BUILD_ARCH )

tmp="/tmp/extrepo.$$.raw.txt"

extrepo search >"${tmp}"

archOptions=$( awk '{
	posA=index( $0, "Architectures:" ) ;
	if( posA > 0 ){
		gsub( /Architectures: /, "", $0 ) ;
		for( i=1 ; i <= NF ; i++ ){
			print $i ;
		} ;
	} ;
}' <"${tmp}" | sort | uniq | awk -v harch="${hostArch}" '{ if( $1 != "all" && $1 != harch ){ printf("%s ", $1 ) ; } ; }' )

selectArch

if [ -z "${choice}" ]
then
	echo "\n Process abandoneed!\n" >&2 ; exit 1
fi

	####################################################################################
	###
	###	Typical report format for repositories
	###
	####################################################################################

	#Found sury_apache2:
	#---
	#description: Ondřej Surý's package repository
	#gpg-key-checksum:
	#  sha256: 59961c0e0d9c9415c2a6b8cf7355bc48254ab53c7e1b8211b683eb459353da81
	#gpg-key-file: sury_apache2.asc
	#policy: main
	#source:
	#  Architectures: amd64 armhf arm64
	#  Components: main
	#  Suites: bookworm
	#  Types: deb deb-src
	#  URIs: https://packages.sury.org/apache2

	####################################################################################

awk -v arch="${choice}" 'BEGIN{
	capture=0 ;
	indx=0 ;
	archCount=0 ;
	split("", datLine ) ;
}{
	posA=index( $0, "Architectures:" ) ;
	if( posA > 0 ){
		#  Architectures: amd64 armhf arm64
		archMatch=0 ;
		rem=substr( $0, posA+15 ) ;
		n=split( rem, vals ) ;
		for( j=1 ; j <= n ; j++ ){
			if( vals[j] == arch ){
				archMatch=1 ;
				break
			} ;
		} ;
	} ;
	if( index( $0, "Found" ) == 1 ){
		if( archMatch == 1 && indx > 1 ){
			archCount++ ;
			for( i=1 ; i <= indx ; i++ ){
				print datLine[i] ;
			} ;
			archMatch=0 ;
			split("", datLine ) ;
		} ;
		capture=1 ;
		indx=1 ;
	} ;
	if( capture == 1 ){
		indx++ ;
		datLine[indx]=$0 ;
	} ;
}END{
	if( archMatch == 1 && indx > 1 ){
		archCount++ ;
		for( i=1 ; i <= indx ; i++ ){
			print datLine[i] ;
		} ;
	} ;
	printf("\nMatches on \"%s\" Architecture: %d\n", arch, archCount ) ;
}' <"${tmp}"


exit

If anyone knows how to make the YAD "button list" more of a button grid, I would greatly appreciate learning how to accomplish that.
:slight_smile:

2 Likes

Works like a charm :smiling_face:

If you want more than one column in yad, use the --column option multiple times.

Taking your example, that would result in:

yad --list --title "ACTION - Choose Architecture" \
	--text "Double-Click on your selection:\n" \
	--width=800 \
	--height=450 \
	--column "first column" \
	--column "second column" \
	--column "third column" \
	${hostArch} ${archOptions} \
	--no-headers | sed 's+[|]$++' )

Be aware that the columns are filled row by row from left to right. :slight_smile:

1 Like

Somehow I missed this.

I very much like this tool!

1 Like

Thanks again, Thom! Unfortunately, the multiple usage of "--column" will spread the values across the columns, but the resulting response is a multi-valued, pipe-separated response, which is not the single-value response from a single "array-box button", which is what I need for that to work.

I've put in my enhancement request to the developper:

2 Likes

Oops, you're right.
And buttons will also not work in a grid. :thinking:

I had success with checkboxes in a grid when making an objective bash shoppinglist (proof of concept thing), but I don't think that will fulfill the need in this given context.

So I am afraid that what you want is not possible in yad
(for I guess that having 3 or 4 comboboxes as a replacement is not really an elegant solution)

There are, however, other frontends for bash, like
dialogbox , gtkdialog (code is here) and gtkserver which have way more possibilities than yad

Some examples:

Example of an old gtkdialog project of mine:

Example of a dialogbox project that I have to finish:

Example of what you can do with gtkserver:


(this last one is not written by me but is a demo from the gtkserver website)

2 Likes

Thanks again, Thom. I'll keep those suggestions for future reference.

For now, I think I will stick with my original single-column approach for my script. That way, I know I am getting the correct value returned.

I'm in the process of tweaking the script to incorporate both

  • the above-mentionned one-liner (global, not ARCH-specific; that might change),       and
  • additional flags to provide either the full, detailed, ARCH-specific repository report, and also a full, ARCH-specific summary-only which would provide, for each, the name ("Found" lines) accompanied by just the "Description:" contents.

:slight_smile:



Updated script [Version 3] to offer ARCH-specific summary-only one-liner for each repository.

Updated script [Version 4] to present ARCH-specific selector buttons in more compact 4-column array with all the identified choices.

#!/bin/bash

###
###	Script to report availability of non-Distro repositories
###	for user-selected Architecture (default is that of computer)
###
###	The "extrepo" command offers a method which offers better
###	integration of such repositories for managing and security
###
###	Version 4
###

details=0
headers=0
pkgs=0
new=0
this=$$

while [ $# -gt 0 ]
do
	case "${1}" in
		"--verbose" )
			details=1 ; shift ;;
		"--brief" )
			headers=1 ; shift ;;
		"--titles" )
			pkgs=1 ; shift ;;
		"--refresh" )
			new=1 ; shift ;;
		* )
			echo -e "\n Invalid option '${1}' specfied on command line.\n" ; exit 1 ;;
	esac
done


buildMenu()
{
	width=100
	max=$(echo ${archOptions} | wc -w | awk '{ print $1 }' )
	indx=0
	echo -e "yad --title \"ACTION - Choose Architecture\" --width=600 --height=300 --form --text \"Double-Click on your selection:\n\" --columns=4 --noheaders \\"
	echo -e "--column="Optn1":100 --column="Optn2":100 --column="Optn3":100 --column="Optn4":100 \\"

	for arch in ${hostArch} $(echo ${archOptions} )
	do
		if [ ${indx} -eq ${max} ]
		then
			echo -e "--field=\"${arch}\":fbtn \"bash -c 'echo ${arch}'\" "
		else
			echo -e "--field=\"${arch}\":fbtn \"bash -c 'echo ${arch}'\" \\"
		fi
		indx=$(expr ${indx} + 1 )
		#--field="1":fbtn "bash -c 'echo 1'" \
	done
	echo -e ""
}


selectArch()
{
	"${men}" >"${val}" 2>>/dev/null &
	yadPID=$!
	yadPID=$(ps -ef | grep ${yadPID} | grep 'yad' | awk '{ print $2 }' )

	#ls -l "${val}"
	#echo ${yadPID}

	inotifywait -m -e modify "${val}" 2>>/dev/null |
	while read -r notifyline ; do
		#echo "${notifyline}"
		testor=$(head -1 "${val}" )
		#echo "${testor}"
		if [ -n "${testor}" ]
		then
			sync
			kill -9 ${yadPID}
			notifPID=$(ps -ef | grep 'inotifywait' | grep ${this} | awk '{ print $2 }' )
			kill -9 ${notifPID}
			break
		fi
	done

	#choice=$(grep -v "|" "${val}" )
	choice=$(head -1 "${val}" )
	if [ -z "${choice}" ]
	then
		echo -e "\n No choice made. Process abandoned!\n" ; exit 1
	fi

	#echo ${choice}
}


	########################################################################
	########################################################################


hostArch=$( dpkg-architecture -q DEB_BUILD_ARCH )

tmp="/tmp/extrepoArch.raw.txt"
men="/tmp/extrepoArch.men.txt"
val="/tmp/extrepoArch.val.txt" ; rm -f "${val}" ; touch "${val}"

if [ ! -s "${tmp}" ]
then
	new=1
fi

if [ ${new} -eq 1 ]
then
	rm -f "${tmp}"
	extrepo search >"${tmp}"
else
	echo -e "\n Re-using recently generated raw 'extrepo' report:" >&2
	ls -l "${tmp}" | awk '{ printf("\t %s\n", $0 ) ; }' >&2
	if [ ${pkgs} -eq 1 ]
	then
		sleep 5
	fi
fi

if [ ${pkgs} -eq 1 ]
then
	grep '^Found' "${tmp}" | sort | sed 's+^Found ++'  | sed 's+[:]$++'
	exit 0
fi


archOptions=$( awk '{
	posA=index( $0, "Architectures:" ) ;
	if( posA > 0 ){
		gsub( /Architectures: /, "", $0 ) ;
		for( i=1 ; i <= NF ; i++ ){
			print $i ;
		} ;
	} ;
}' <"${tmp}" | sort | uniq | awk -v harch="${hostArch}" '{ if( $1 != "all" && $1 != harch ){ printf("%s ", $1 ) ; } ; }' ) 



buildMenu >"${men}"

chmod 744 "${men}"


selectArch

if [ -z "${choice}" ]
then
	echo -e "\n Process abandoneed!\n" >&2 ; exit 1
fi

	####################################################################################
	###
	###	Typical report format for repositories
	###
	####################################################################################

	#Found sury_apache2:
	#---
	#description: Ondřej Surý's package repository
	#gpg-key-checksum:
	#  sha256: 59961c0e0d9c9415c2a6b8cf7355bc48254ab53c7e1b8211b683eb459353da81
	#gpg-key-file: sury_apache2.asc
	#policy: main
	#source:
	#  Architectures: amd64 armhf arm64
	#  Components: main
	#  Suites: bookworm
	#  Types: deb deb-src
	#  URIs: https://packages.sury.org/apache2

	####################################################################################

awk -v heads="${headers}" -v arch="${choice}" 'BEGIN{
	capture=0 ;
	indx=0 ;
	archCount=0 ;
	descrB=0 ;
	rname=0 ;
	first=0 ;
	split("", datLine ) ;
}{
	posA=index( $0, "Architectures:" ) ;
	if( posA > 0 ){
		#  Architectures: amd64 armhf arm64
		archMatch=0 ;
		rem=substr( $0, posA+15 ) ;
		n=split( rem, vals ) ;
		for( j=1 ; j <= n ; j++ ){
			if( vals[j] == arch ){
				archMatch=1 ;
				break
			} ;
		} ;
	} ;

	if( heads == 1 ){
		testor=substr( $0, 1, 1 ) ;
		if( $0 ~ /^[a-zA-Z]/ || $0 == "---" ){
			descrB=0 ;
			capture=0 ;
		} ;
	} ;

	if( index( $0, "Found" ) == 1 ){
		if( archMatch == 1 && indx > 1 ){
			archCount++ ;
			if( heads == 1 ){
				printf("%s ※ ", datLine[2] ) ;
				is=3 ;
			}else{
				print datLine[1] ;
				is=2 ;
			} ;
			for( i=is ; i <= indx ; i++ ){
				if( heads == 1 ){
					sub( /^[ ][ ]/, "", datLine[i] ) ;
					printf("%s ", datLine[i] ) ;
				}else{
					print datLine[i] ;
				} ;
			} ;
			if( heads == 1 ){
				printf("\n") ;
			} ;
			archMatch=0 ;
			split("", datLine ) ;
		} ;
		capture=1 ;
		indx=1 ;
		rname=1 ;
	} ;

	if( index( $0, "description:" ) == 1 ){
		descrB=1 ;
		capture=1 ;
		first=1 ;
	} ;

	if( capture == 1 ){
		indx++ ;
		if( rname == 1 && heads == 1 ){
			datLine[indx]=substr( $0, 7 ) ;
			sub( /[:]$/, "", datLine[indx] ) ;
		}else{
			if( descrB == 1 && first == 1 && heads == 1  ){
				datLine[indx]=substr( $0, 14 ) ;
				first=0 ;
			}else{
				datLine[indx]=$0 ;
			} ;
		} ;
		rname=0 ;
	} ;
}END{
	if( archMatch == 1 && indx > 1 ){
		archCount++ ;
		if( heads == 1 ){
			printf("%s ※ ", datLine[2] ) ;
			is=3
		}else{
			print datLine[1] ;
			is=2
		} ;
		for( i=is ; i <= indx ; i++ ){
			if( heads == 1 ){
				sub( /^[ ][ ]/, "", datLine[i] ) ;
				printf("%s ", datLine[i] ) ;
			}else{
				print datLine[i] ;
			} ;
		} ;
		if( heads == 1 ){
			printf("\n") ;
		} ;
	} ;
	if( heads == 1 ){
		nl1="" ;
		nl2="\n" ;
	}else{
		nl1="\n" ;
		nl2="" ;
	} ;
	printf("%sMatches on \"%s\" Architecture: %d\n%s", nl1, arch, archCount, nl2 ) | "cat 1>&2" ;
}' <"${tmp}" |
{
	if [ ${headers} -eq 1 ]
	then
		sort
	else
		cat
	fi
}


exit
1 Like

Truely an unconventional mix of both a GUI and commandline options :slight_smile:

Wouldn't it more convenient to go either full GUI or full commandline ? (TUI would also be an option)

2 Likes

I saw this as an opportunity to explore and "feel out" what I could achieve using YAD (which some claim to be superior to zenity; I don't know either so have no opinion as to the superiority of either one. :slight_smile: )

Wanted to get my "sea legs" before commiting to using it as part of my attempt to add a User-selection "wrapper" for the install/configure of a MATE-based environment built from an underlying Ubuntu Server ISO.

2 Likes

Ah, yes, that is completely logical :slight_smile:

2 Likes