autils

A minimal package manager written for Alice Linux
git clone https://codeberg.org/emmett1/autils
Log | Files | Refs | README | LICENSE

apkg (24184B)


      1 #!/bin/sh
      2 #    ______   ______  __  __   ______   
      3 #   /\  __ \ /\  == \/\ \/ /  /\  ___\  
      4 #   \ \  __ \\ \  _-/\ \  _"-.\ \ \__ \ 
      5 #    \ \_\ \_\\ \_\   \ \_\ \_\\ \_____\
      6 #     \/_/\/_/ \/_/    \/_/\/_/ \/_____/
      7 #
      8 # APKG - Alice Package Manager (C) 2023-2025 Emmett1
      9 #
     10 
     11 fetch_src() {
     12 	[ "$source" ] || return 0
     13 	for i in $source; do
     14 		i=${i%::noextract}
     15 		case $i in
     16 			*::*) sn=${i%::*};;
     17 			   *) sn=${i##*/};;
     18 		esac
     19 		case ${i#*::} in
     20 			http://*|https://*|ftp://*)
     21 				if [ ! -f $APKG_SOURCE_DIR/$sn ]; then
     22 					[ -f $APKG_SOURCE_DIR/$sn.tmp ] && resume="-C -"
     23 					msg "fetching ${i#*::}"
     24 					curl $resume --fail --retry 3 --retry-delay 3 -L -o $APKG_SOURCE_DIR/$sn.tmp ${i#*::} || {
     25 						msg "Failed downloading source '$sn'."
     26 						exit 1
     27 					}
     28 					mv $APKG_SOURCE_DIR/$sn.tmp $APKG_SOURCE_DIR/$sn
     29 				fi;;
     30 		esac
     31 	done
     32 }
     33 
     34 extract_src() {
     35 	prepare_workdir
     36 	[ "$source" ] || return 0
     37 	checksource
     38 	for i in $source; do
     39 		case $i in
     40 			*/*) S=$APKG_SOURCE_DIR;;
     41 			  *) S=$HERE;;
     42 		esac
     43 		case ${i%::noextract} in
     44 			*::*) sn=${i%%::*};;
     45 			   *) sn=${i##*/}; sn=${sn%::noextract};;
     46 		esac
     47 		case $i in
     48 			*::noextract)
     49 				i=${i%::noextract}
     50 				cp $S/$sn $SRC || {
     51 					msg "Failed copy '$S/$sn' to '$SRC'."
     52 					ret 1
     53 				};;
     54 			*.tar.bz2|*.tar.gz|*.tar.lz|*.tar.lzma|*.tar.lzo|*.tar.xz|*.tar.Z|*.tb2|*.tbz|*.tbz2|*.tz2|*.taz|*.tgz|*.tlz|*.txz|*.tZ|*.taZ)
     55 				msg "Unpacking '$S/$sn'..."
     56 				tar -p -o -C $SRC -xf $S/$sn || {
     57 					msg "Failed unpacking source '${i##*/}'."
     58 					ret 1
     59 				};;
     60 			*) 
     61 				i=${i%::noextract}
     62 				cp $S/$sn $SRC || {					
     63 					msg "Failed copy '$S/$sn' to '$SRC'."
     64 					ret 1
     65 				};;
     66 		esac
     67 	done
     68 }
     69 
     70 prepare_workdir() {
     71 	export SRC=$APKG_WORK_DIR/apkg-src-${PWD##*/}
     72 	export PKG=$APKG_WORK_DIR/apkg-pkg-${PWD##*/}
     73 	
     74 	remove_workdir
     75 	mkdir -p "$PKG" "$SRC"	
     76 }
     77 
     78 remove_workdir() {
     79 	rm -rf "$PKG" "$SRC"
     80 }
     81 
     82 ret() {	
     83 	[ "$APKG_KEEP_WORKDIR" ] || remove_workdir
     84 	exit $1
     85 }
     86 
     87 detect_buildtype() {
     88 	if [ -f meson.build ]; then
     89 		build_type=meson_build
     90 	elif [ -f configure ]; then
     91 		build_type=configure_build
     92 	elif [ -f CMakeLists.txt ]; then
     93 		build_type=cmake_build
     94 	elif [ -f setup.py ]; then
     95 		build_type=python_build
     96 	elif [ -f Makefile.PL ]; then
     97 		build_type=perlmodule_build
     98 	elif [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ]; then
     99 		build_type=makefile_build
    100 	else
    101 		msg "failed to detect buildtype"
    102 		ret 1
    103 	fi
    104 }
    105 
    106 _makefile_build() {
    107 	make \
    108 		PREFIX=/usr \
    109 		prefix=/usr \
    110 		SYSCONFDIR=/etc \
    111 		sysconfdir=/etc \
    112 		MANDIR=/usr/share/man \
    113 		mandir=/usr/share/man \
    114 		LIBDIR=/usr/lib \
    115 		PKGCONFIGDIR=/usr/lib/pkgconfig
    116 	make \
    117 		PREFIX=/usr \
    118 		prefix=/usr \
    119 		SYSCONFDIR=/etc \
    120 		sysconfdir=/etc \
    121 		MANDIR=/usr/share/man \
    122 		mandir=/usr/share/man \
    123 		LIBDIR=/usr/lib \
    124 		PKGCONFIGDIR=/usr/lib/pkgconfig \
    125 		DESTDIR=$PKG install
    126 }
    127 
    128 _perlmodule_build() {
    129 	perl Makefile.PL
    130 	make
    131 	make DESTDIR=$PKG install
    132 }
    133 
    134 _cmake_build() {
    135 	mkdir -p cmakebuild
    136 	cd cmakebuild
    137 	cmake \
    138 		-DCMAKE_INSTALL_PREFIX=/usr \
    139 		-DCMAKE_INSTALL_SYSCONFDIR=/etc \
    140 		-DCMAKE_INSTALL_LIBDIR=lib \
    141 		-DCMAKE_BUILD_TYPE=Release \
    142 		-DFETCHCONTENT_FULLY_DISCONNECTED=ON \
    143 		-DCMAKE_C_FLAGS_RELEASE="$CFLAGS" \
    144 		-DCMAKE_CXX_FLAGS_RELEASE="$CXXFLAGS" \
    145 		$build_opt \
    146 		-B build ..
    147 	if [ -f build.ninja ]; then
    148 		ninja
    149 		DESTDIR=$PKG ninja install
    150 	else
    151 		cmake --build build
    152 		DESTDIR=$PKG cmake --install build
    153 	fi
    154 }
    155 
    156 _python_build() {
    157 	python3 setup.py build
    158 	python3 setup.py install --prefix=/usr --root=$PKG --optimize=1 $build_opt
    159 }
    160 
    161 _configure_build() {
    162 	./configure \
    163 		--prefix=/usr \
    164 		--sysconfdir=/etc \
    165 		--localstatedir=/var \
    166 		--libdir=/usr/lib \
    167 		--infodir=/usr/share/info \
    168 		--mandir=/usr/share/man \
    169 		$build_opt
    170 	make
    171 	make DESTDIR=$PKG install
    172 }
    173 
    174 _meson_build() {
    175 	meson setup \
    176 		-Dprefix=/usr \
    177 		-Dlibdir=/usr/lib \
    178 		-Dincludedir=/usr/include \
    179 		-Ddatadir=/usr/share \
    180 		-Dmandir=/usr/share/man \
    181 		-Dinfodir=/usr/share/info \
    182 		-Dlocaledir=/usr/share/locale \
    183 		-Dsysconfdir=/etc \
    184 		-Dlocalstatedir=/var \
    185 		-Dsharedstatedir=/var/lib \
    186 		-Dbuildtype=plain \
    187 		-Dauto_features=auto \
    188 		-Dwrap_mode=nodownload \
    189 		-Db_lto=true \
    190 		-Db_pie=true \
    191 		$build_opt \
    192 		build
    193 	ninja -C build
    194 	DESTDIR=$PKG meson install -C build
    195 }
    196 
    197 apply_patch() {
    198 	[ "$skip_patch" ] && {
    199 		unset skip_patch # allowing manual patch in build() using apply_patch
    200 		return 0
    201 	}
    202 	if [ "$source" ]; then
    203 		for p in $source; do
    204 			case ${p%::noextract} in
    205 				*::*) pn=${p%::*};;
    206 				   *) pn=${p##*/};;
    207 			esac
    208 			case $pn in
    209 				*.patch|*.diff)
    210 					msg "applying patch '$SRC/$pn'."
    211 					patch ${patch_opt:--p1} -t -i $SRC/$pn || ret 1;;
    212 			esac
    213 		done
    214 	fi
    215 }
    216 
    217 msg() {
    218 	# Don't bother if we're not in a terminal
    219     if [ -t 1 ]; then
    220         ttysize=$(stty size 2>/dev/null | awk '{print $2}' || echo "80")
    221     fi
    222     printf "%s\n" "[${name:-...}] $@" | fold -sw ${ttysize:-80}
    223 }
    224 
    225 buildstatus() {
    226 	[ "$?" = 0 ] || {
    227 		msg "build package '$name-$version-$release' failed on '$1'."
    228 		ret 1
    229 	}
    230 }
    231 
    232 build_src() {
    233 	cd $SRC
    234 	
    235 	if [ "$build_dir" ]; then
    236 		if [ ! -d "$build_dir" ]; then
    237 			msg "Source directory '$build_dir' not found."
    238 			ret 1
    239 		fi
    240 	elif [ -d $name-$version ]; then
    241 		build_dir=$name-$version
    242 	elif [ -d "$(ls -1 --group-directories-first | head -n1)" ]; then
    243 		build_dir=$(ls -1 --group-directories-first | head -n1)
    244 	fi
    245 	
    246 	# cd into extracted source directory
    247 	if [ "$build_dir" ]; then
    248 		cd $build_dir
    249 	fi
    250 	
    251 	apply_patch
    252 
    253 	export CARGO_HOME=${CARGO_HOME:-$SRC/.cargo}
    254 	export GOCACHE=${GOCACHE:-$SRC/.go}
    255 	export DESTDIR=$PKG
    256 	export DEST_DIR=$PKG     # p7zip
    257 	export INSTALLROOT=$PKG  # syslinux
    258 	export install_root=$PKG # glibc
    259 	export INSTALL_ROOT=$PKG # qt5
    260 
    261 	if [ ! "$source" ]; then
    262 		# dummy pkg
    263 		mkdir -p $PKG/usr
    264 	elif [ "$(command -v build)" ]; then
    265 		(set -e -x; build)
    266 		buildstatus build
    267 	else
    268 		if [ "$(command -v prebuild)" ]; then
    269 			(set -e -x; prebuild)
    270 			buildstatus prebuild
    271 		fi
    272 		if [ ! "${build_type}" ]; then
    273 			detect_buildtype
    274 		fi
    275 		(set -e -x; _${build_type})
    276 		buildstatus ${build_type}
    277 		if [ "$(command -v postbuild)" ]; then
    278 			(set -e -x; postbuild)
    279 			buildstatus postbuild
    280 		fi
    281 	fi
    282 	
    283 	msg "build $name-$version-$release success"
    284 	
    285 	# compress man pages
    286 	if [ -d $PKG/usr/share/man ]; then
    287 		# only keep man[1-8] man pages
    288 		for m in $PKG/usr/share/man/*; do
    289 			case ${m##*/} in
    290 				man[1-8]) continue;;
    291 			esac
    292 			rm -rf $m
    293 		done
    294 		for i in $(find $PKG/usr/share/man -type f); do
    295 			[ $i = ${i%%.gz} ] || continue
    296 			gzip -9 $i
    297 		done
    298 		for i in $(find $PKG/usr/share/man -type l) ; do
    299 			ln -s $(readlink $i).gz ${i%.gz}.gz
    300 			rm $i
    301 		done
    302 	fi
    303 
    304 	# compress info pages
    305 	if [ -d $PKG/usr/share/info ]; then
    306 		rm -f $PKG/usr/share/info/dir
    307 		find $PKG/usr/share/info -type f -exec gzip -9 {} \;
    308 	fi
    309 	
    310 	# possible conflicts
    311 	find $PKG -name "fonts.dir" -exec rm {} \;
    312 	find $PKG -name "fonts.scale" -exec rm {} \;
    313 	find $PKG -name "perllocal.pod" -exec rm {} \;
    314 	find $PKG -name "charset.alias" -exec rm {} \;
    315 	
    316 	if [ ! "$keep_static" ]; then
    317 		find $PKG -name "*.a" -exec rm {} \;
    318 	fi
    319 	
    320 	if [ ! "$keep_libtool" ]; then
    321 		find $PKG -name "*.la" -exec rm {} \;
    322 	fi
    323 	
    324 	if [ ! "$keep_locale" ]; then
    325 		rm -rf $PKG/usr/share/locale
    326 		rm -rf $PKG/usr/lib/locale
    327 	fi
    328 	
    329 	if [ ! "$keep_doc" ]; then
    330 		rm -rf $PKG/usr/share/doc
    331 		rm -rf $PKG/usr/doc
    332 	fi
    333 	
    334 	# strip binaries and libraries
    335 	if [ ! "$no_strip" ]; then
    336 		find $PKG | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs ${CROSS_COMPILE}strip --strip-all 2>/dev/null
    337 		find $PKG | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs ${CROSS_COMPILE}strip --strip-unneeded 2>/dev/null
    338 		find $PKG | xargs file | grep "current ar archive" | cut -f 1 -d : | xargs ${CROSS_COMPILE}strip --strip-debug 2>/dev/null
    339 	fi
    340 	
    341 	# usrmerge
    342 	if [ "$APKG_BINMERGE" ]; then
    343 		for b in bin sbin usr/sbin; do
    344 			if [ -d $PKG/$b ]; then
    345 				mkdir -p $PKG/usr/bin
    346 				mv $PKG/$b/* $PKG/usr/bin
    347 				rm -rf $PKG/$b
    348 			fi
    349 		done
    350 	fi
    351 		
    352 	# runit service
    353 	for s in $sv; do
    354 		[ -f $SRC/$s ] || ret 1
    355 		case $s in
    356 				 run) install -Dm755 $SRC/$s $PKG/etc/sv/$name/run
    357 					  ln -s ../../../run/runit/supervise.$name $PKG/etc/sv/$name/supervise;;
    358 			  finish) install -Dm755 $SRC/$s $PKG/etc/sv/$name/finish;;
    359 			   *.run) install -Dm755 $SRC/$s $PKG/etc/sv/${s%.*}/run
    360 					  ln -s ../../../run/runit/supervise.${s%.*} $PKG/etc/sv/${s%.*}/supervise;;
    361 			*.finish) install -Dm755 $SRC/$s $PKG/etc/sv/${s%.*}/finish;;
    362 				 *.*) install -Dm644 $SRC/$s $PKG/etc/sv/${s%%.*}/${s#*.};;
    363 				   *) install -Dm644 $SRC/$s $PKG/etc/sv/$name/$s;;
    364 		esac
    365 	done
    366 		
    367 	if [ ! "$(ls -1 $PKG)" ]; then
    368 		msg "\$PKG is empty"
    369 		ret 1
    370 	fi
    371 	
    372 	# temporary: for backward compatibility
    373 	if [ "$(grep '#MARKER' /usr/bin/spm)" ]; then
    374 		cd $PKG
    375 		spm -b $packagefile || {
    376 			msg "Failed packaging $packagefile"
    377 			ret 1
    378 		}
    379 	else
    380 		cd $APKG_PACKAGE_DIR
    381 		spm -b $PKG && {
    382 			mv package.spm $packagefile
    383 		} || {
    384 			msg "Failed packaging $packagefile"
    385 			ret 1
    386 		}
    387 	fi
    388 	
    389 	if [ ! -f "$HERE"/.files ] || [ "$HERE"/abuild -nt "$HERE"/.files ]; then
    390 		pkg_updatefiles
    391 	fi
    392 
    393 	cd $HERE
    394 	remove_workdir
    395 }
    396 
    397 pkg_updatefiles() {
    398 	if [ ! -f "$packagefile" ]; then
    399 		msg "Package '$packagefile' not found."
    400 		ret 1
    401 	fi
    402 	msg "filelist updated."
    403 	tar -tvf $packagefile | awk '{$3=$4=$5=""; print $0}' | sort -k 3 > "$HERE"/.files
    404 }
    405 
    406 pkg_path() {
    407 	for p in $@; do
    408 		for r in $APKG_REPO; do
    409 			[ -f $r/$p/abuild ] && {
    410 				printf "%s\n" $r/$p
    411 				break
    412 			}
    413 		done
    414 	done
    415 }
    416 
    417 die() {
    418 	[ "$1" ] && printf "%s\n" "error: $1"
    419 	ret 1
    420 }
    421 
    422 checkdep() {
    423 	[ "$(pkg_path $1)" ] || return
    424 	# track processed pkg to avoid cycle deps
    425 	process="$process $1"
    426 	for ii in $(pkg_depends $1); do
    427 		# if already installed, skip
    428 		if [ "$skip_installed" ]; then
    429 			[ -s $SPM_PKGDB/$ii ] && continue
    430 		fi
    431 		# if deps already in process list, skip, cycle deps detected
    432 		printf "%s\n" $process | tr ' ' '\n' | grep -qx $ii && continue
    433 		# skip if itself in depends list
    434 		[ "$ii" = "$1" ] && continue
    435 		# skip if pkg already in deps list
    436 		printf "%s\n" $DEPS | tr ' ' '\n' | grep -x $ii && continue
    437 		# check deps
    438 		checkdep $ii
    439 	done
    440 	# will go here if no deps anymore to check, add it to list deps
    441 	DEPS="$DEPS $1"
    442 }
    443 
    444 pkg_deplist() {
    445 	for i in $@; do
    446 		# if already have in list deps, dont check again
    447 		if [ ! $(printf "%s\n" $DEPS | tr ' ' '\n' | grep -x $i) ]; then
    448 			checkdep $i
    449 		fi
    450 	done
    451 	printf "%s\n" $DEPS | tr ' ' '\n'
    452 }
    453 
    454 pkg_fsearch() {
    455 	for r in $APKG_REPO; do
    456 		rr="$rr $r/*/.files"
    457 	done
    458 	grep $1 $rr 2>/dev/null | tr ':' ' ' | awk '{print $1,$4}' | sed 's,/.files,,g'
    459 }
    460 
    461 pkg_dependents() {
    462 	for r in $APKG_REPO; do
    463 		rr="$rr $r/*/depends"
    464 	done
    465 	grep -x $1 $rr 2>/dev/null | rev | cut -d / -f 2 | rev
    466 }
    467 
    468 pkg_depends() {
    469 	_path=$(pkg_path $1) || return 1
    470 	[ -s $_path/depends ] || return
    471 	solve_alias $(grep -Ev ^'(#|$)' $_path/depends | awk '{print $1}')
    472 }
    473 
    474 solve_alias() {
    475 	[ "$APKG_ALIAS" ] || {
    476 		printf "%s\n" $@
    477 		return
    478 	}
    479 	while [ "$1" ]; do
    480 		d=$(printf "%s\n" $APKG_ALIAS | tr ' ' '\n' | grep ^$1:* | head -n1 | awk -F : '{print $2}')
    481 		printf "%s\n" ${d:-$1}
    482 		shift
    483 	done
    484 }
    485 
    486 pkg_outdate() {
    487 	verbose=1 pkg_allinstalled | while read -r n v; do
    488 		if [ "$mask" ]; then
    489 			[ "$APKG_MASK" ] && {
    490 				printf "%s\n" "$APKG_MASK" | tr ' ' '\n' | grep -xq $n && continue
    491 			}
    492 		fi
    493 		[ "$(pkg_path $n)" ] || continue
    494 		nv="$(grep ^version= $(pkg_path $n)/abuild | tail -n1 | awk -F = '{print $2}')-$(grep ^release= $(pkg_path $n)/abuild | awk -F = '{print $2}')"
    495 		[ "$nv" ] || continue
    496 		[ "$v" = "$nv" ] || printf "%s\n" "$n $v -> $nv"
    497 	done
    498 }
    499 
    500 pkg_remove() {
    501 	needroot
    502 	for i in $@; do
    503 		SPM_ROOT=$APKG_ROOT spm -r $i
    504 	done
    505 }
    506 
    507 pkg_sysup() {
    508 	needroot
    509 	msg "Checking for outdated packages..."
    510 	od=$(mask=1 pkg_outdate | awk '{print $1}')
    511 	if [ ! "$od" ]; then
    512 		msg "No outdated packages."
    513 		exit 0
    514 	else
    515 		msg "Solving dependencies..."
    516 		for p in $(pkg_deplist $od); do
    517 			[ -s $SPM_PKGDB/$p ] || ni="$ni $p"
    518 			printf "%s\n" $od | tr ' ' '\n' | grep -qx $p && pu="$pu $p"
    519 		done
    520 		if [ "$ni" ]; then
    521 			newpkg=$(printf "%s\n" $ni | tr ' ' '\n' | wc -l)
    522 			msg "Installing $newpkg new package(s): $ni"
    523 		fi
    524 		totalpkg=$(printf "%s\n" $pu | tr ' ' '\n' | wc -l)
    525 		msg "Upgrading $totalpkg package(s): $pu"
    526 		prompt_user
    527 		if [ "$ni" ]; then
    528 			$APKG -i $ni #|| die
    529 		fi
    530 		$APKG -u $pu #|| die
    531 	fi
    532 }
    533 
    534 pkg_search() {
    535 	if [ ! "$APKG_REPO" ]; then
    536 		msg "No repo configured."
    537 		exit 1
    538 	fi
    539 	if [ "$pkg" ]; then
    540 		for p in $pkg; do
    541 			grep="$grep -e $p"
    542 		done
    543 		grep="grep $grep"
    544 	else
    545 		grep=cat
    546 	fi
    547 	[ "$verbose" ] && {
    548 		find $APKG_REPO -type f -name abuild 2>/dev/null | sed 's|/abuild||' | rev | awk -F / '{print $1}' | rev | $grep | while read line; do printf "$line "; awk -F'=' '/^version/ {print $2}' $($APKG -p $line)/abuild ; done
    549 	} || {
    550 		find $APKG_REPO -type f -name abuild 2>/dev/null | sed 's|/abuild||' | rev | awk -F / '{print $1}' | rev | $grep
    551 	}
    552 }
    553 
    554 pkg_depinstalll() {
    555 	needroot
    556 	for p in $@; do
    557 		if [ -s $SPM_PKGDB/$p ]; then
    558 			msg "Package '$p' is installed"
    559 			continue
    560 		fi
    561 		if [ ! "$(pkg_path $p)" ]; then
    562 			msg "Package '$p' not found"
    563 			continue
    564 		fi
    565 		pkg="$pkg $p"
    566 	done
    567 	[ "$pkg" ] || exit 0
    568 	set -- $pkg
    569 	msg "Solving dependencies..."
    570 	for p in $(skip_installed=1 pkg_deplist $@); do
    571 		[ -s $SPM_PKGDB/$p ] && continue
    572 		installthis="$installthis $p"
    573 	done
    574 	if [ ! "$installthis" ]; then
    575 		msg "Nothing to install. Exiting..."
    576 		exit 0
    577 	fi
    578 	totalpkg=$(printf "%s\n" $installthis | tr ' ' '\n' | wc -l)
    579 	msg "Installing $totalpkg package(s): $installthis"
    580 	prompt_user
    581 	$APKG -i $installthis || die
    582 }
    583 
    584 _trigger_fccache() {
    585 	command -v fc-cache >/dev/null || return 0
    586 	spm -l $1 | grep -q ^usr/share/fonts/$ && {
    587 		msg "Updating fontconfig cache..."
    588 		fc-cache -sf
    589 	}
    590 }
    591 
    592 _trigger_gdkpixbufcache() {
    593 	command -v gdk-pixbuf-query-loaders >/dev/null || return 0
    594 	spm -l $1 | grep -q ^usr/lib/gdk-pixbuf-2.0/2.10.0/loaders/$ && {
    595 		msg "Probing GDK-Pixbuf loader modules..."
    596 		gdk-pixbuf-query-loaders --update-cache
    597 	}
    598 }
    599 
    600 _trigger_giomodules() {
    601 	command -v gio-querymodules >/dev/null || return 0
    602 	spm -l $1 | grep -q ^usr/lib/gio/modules/$ && {
    603 		msg "Updating GIO module cache..."
    604 		gio-querymodules /usr/lib/gio/modules
    605 	}
    606 }
    607 
    608 _trigger_glibschema() {
    609 	command -v glib-compile-schemas >/dev/null || return 0
    610 	spm -l $1 | grep -q ^usr/share/glib-2.0/schemas/$ && {
    611 		msg "Compiling GSettings XML schema files..."
    612 		glib-compile-schemas /usr/share/glib-2.0/schemas
    613 	}
    614 }
    615 
    616 _trigger_gtk2immodules() {
    617 	command -v gtk-query-immodules-2.0 >/dev/null || return 0
    618 	spm -l $1 | grep -q ^usr/lib/gtk-2.0/2.10.0/immodules/$ && {
    619 		msg "Probing GTK2 input method modules..."
    620 		gtk-query-immodules-2.0 --update-cache
    621 	}
    622 }
    623 
    624 _trigger_gtk3immodules() {
    625 	command -v gtk-query-immodules-3.0 >/dev/null || return 0
    626 	spm -l $1 | grep -q ^usr/lib/gtk-3.0/3.0.0/immodules/$ && {
    627 		msg "Probing GTK3 input method modules..."
    628 		gtk-query-immodules-3.0 --update-cache
    629 	}
    630 }
    631 
    632 _trigger_iconcache() {
    633 	command -v gtk-update-icon-cache >/dev/null || return 0
    634 	spm -l $1 | grep -q ^usr/share/icons/$ && {
    635 		msg "Updating icon theme caches..."
    636 		for dir in /usr/share/icons/* ; do
    637 			if [ -e $dir/index.theme ]; then
    638 				gtk-update-icon-cache -q $dir 2>/dev/null
    639 			else
    640 				rm -f $dir/icon-theme.cache
    641 				rmdir --ignore-fail-on-non-empty $dir
    642 			fi
    643 		done
    644 	}
    645 }
    646 
    647 _trigger_udevdb() {
    648 	command -v udevadm >/dev/null || return 0
    649 	spm -l $1 | grep -q ^etc/udev/hwdb.d/$ && {
    650 		msg "Updating hardware database..."
    651 		udevadm hwdb --update
    652 	}
    653 }
    654 
    655 _trigger_fontcache() {
    656 	command -v mkfontdir >/dev/null || return 0
    657 	command -v mkfontscale >/dev/null || return 0
    658 	spm -l $1 | grep -q ^usr/share/fonts/$ && {
    659 		msg "Updating X fontdir indices..."
    660 		for dir in $(find /usr/share/fonts -maxdepth 1 -type d \( ! -path /usr/share/fonts \)); do
    661 			rm -f $dir/fonts.scale $dir/fonts.dir $dir/.uuid
    662 			rmdir --ignore-fail-on-non-empty $dir
    663 			[ -d "$dir" ] || continue
    664 			mkfontdir $dir
    665 			mkfontscale $dir
    666 		done
    667 	}
    668 }
    669 
    670 _trigger_desktopdb() {
    671 	command -v update-desktop-database >/dev/null || return 0
    672 	spm -l $1 | grep -q ^usr/share/applications/$ && {
    673 		msg "Updating desktop file MIME type cache..."
    674 		update-desktop-database --quiet
    675 	}
    676 }
    677 
    678 _trigger_mimedb() {
    679 	command -v update-mime-database >/dev/null || return 0
    680 	spm -l $1 | grep -q ^usr/share/mime/$ && {
    681 		msg "Updating the MIME type database..."
    682 		update-mime-database /usr/share/mime
    683 	}
    684 }
    685 
    686 pkg_trigger() {
    687 	needroot
    688 	[ "$@" ] || set -- $($APKG -a)
    689 	for t in mimedb desktopdb fontcache fccache udevdb iconcache gtk3immodules gtk2immodules glibschema giomodules gdkpixbufcache; do
    690 		for p in $@; do
    691 			_trigger_$t $p && break
    692 		done
    693 	done		
    694 }
    695 
    696 pkg_allinstalled() {
    697 	if [ "$pkg" ]; then
    698 		for p in $pkg; do
    699 			grep="$grep -e $p"
    700 		done
    701 		grep="grep $grep"
    702 	else
    703 		grep=cat
    704 	fi
    705 	[ "$verbose" ] && {
    706 		ls -1 $SPM_PKGDB | $grep | while read line; do printf "$line "; head -n1 $SPM_PKGDB/$line ; done
    707 	} || {
    708 		ls -1 $SPM_PKGDB | $grep
    709 	}
    710 }
    711 
    712 checksum_src() {	
    713 	if [ ! -s "$checksum_file" ]; then
    714 		gencsum
    715 	else
    716 		b3sumcheck || return 0
    717 		printcsum > ${checksum_file}.tmp
    718 		diff -U 0 ${checksum_file} ${checksum_file}.tmp | \
    719 			sed '/---/d;/+++/d;/@@/d' | \
    720 			sed 's/^+/ new    : /' | \
    721 			sed 's/^-/ missing: /' > ${checksum_file}.diff
    722 			[ -s "${checksum_file}.diff" ] && {
    723 				cat ${checksum_file}.diff
    724 				msg "Checksum failed."
    725 				failed=1
    726 			}
    727 		rm -f ${checksum_file}.tmp ${checksum_file}.diff
    728 		[ "$failed" ] && ret 1
    729 	fi
    730 }
    731 
    732 printsource() {
    733 	# print out source full path
    734 	for printsource in $source; do
    735 		printsource=${printsource%::noextract}
    736 		case $printsource in
    737 			*::*) sourcename=${printsource%::*};;
    738 			   *) sourcename=${printsource##*/};;
    739 		esac
    740 		case ${printsource#*::} in
    741 			*/*) sourcenamefullpath=${APKG_SOURCE_DIR}/$sourcename;;
    742 			  *) sourcenamefullpath=${HERE}/$sourcename;;
    743 		esac
    744 		printf "%s\n" $sourcenamefullpath
    745 	done
    746 }
    747 
    748 checksource() {
    749 	# check for source existence, exit non-zero if missing
    750 	for checksource in $(printsource); do
    751 		[ -f "$checksource" ] || {
    752 			msg "Source file '$checksource' not found."
    753 			failed=1
    754 		}
    755 	done
    756 	[ "$failed" ] && ret 1
    757 }
    758 
    759 b3sumcheck() {
    760 	command -v b3sum >/dev/null || { msg "'b3sum' not installed."; return 1; }
    761 }
    762 
    763 gencsum() {
    764 	checksource
    765 	b3sumcheck || return 0
    766 	rm -f .checksum
    767 	printcsum > .checksum
    768 	msg "Checksum file updated."
    769 }
    770 
    771 printcsum() {
    772 	for printcsum in $(printsource); do
    773 		[ -f "$printcsum" ] || continue
    774 		b3sum $printcsum | sed "s,$APKG_SOURCE_DIR/,,;s,$HERE/,,"
    775 	done | sort -k 2
    776 }
    777 
    778 prompt_user() {
    779 	if [ ! "$APKG_NOPROMPT" ]; then
    780 		msg "Press ENTER to continue operation."
    781 		msg "Press Ctrl + C to abort."
    782 		read -r null
    783 	fi
    784 }
    785 
    786 runscript() {
    787 	if [ -x ./${1}install ]; then
    788 		msg "Running ${1}install script..."
    789 		if [ "$APKG_ROOT" ]; then
    790 			cat ./${1}install > "$APKG_ROOT"/.runscript
    791 			chmod +x "$APKG_ROOT"/.runscript
    792 			chroot "$APKG_ROOT" /.runscript
    793 			rm -f "$APKG_ROOT"/.runscript
    794 		else
    795 			./${1}install
    796 		fi
    797 	fi
    798 }
    799 
    800 needroot() {
    801 	[ $(id -u) = 0 ] || {
    802 		msg 'This operation need root access'
    803 		exit 1
    804 	}
    805 }
    806 
    807 parsesubopt() {
    808 	# loop opts until found '-*'
    809 	shift; while [ "$1" ]; do
    810 		case $1 in
    811 			-*) break;;
    812 			*) printf "%s\n" "$1";;
    813 		esac
    814 		shift
    815 	done
    816 }
    817 
    818 updateopts() {
    819 	while [ "$1" ]; do
    820 		case $1 in
    821 			-*) newopt="$newopt $1";;
    822 		esac
    823 		shift
    824 	done
    825 	printf "%s\n" "$newopt"
    826 }
    827 
    828 parseopts() {
    829 	while [ "$1" ]; do
    830 		case $1 in
    831 			-I) pkg_depinstalll "$(parsesubopt "$@")"; exit 0;;
    832 			-D) pkg_deplist "$(parsesubopt "$@")"; exit 0;;
    833 			-r) pkg_remove "$(parsesubopt "$@")"; exit 0;;
    834 			-p) pkg_path "$(parsesubopt "$@")"; exit 0;;
    835 			-t) pkg_trigger "$(parsesubopt "$@")"; exit 0;;
    836 			-U) pkg_sysup; exit 0;;
    837 			-d) pkg_depends "$2"; exit 0;;
    838 			-s) search=1;;
    839 			-S) pkg_fsearch "$2"; exit 0;;
    840 			-j) pkg_dependents "$2"; exit 0;;
    841 			-a) allinstalled=1;;
    842 			-h) apkg_help; exit 0;;
    843 			-l) pkg_outdate; exit 0;;
    844 			-g) updatecsum=1;;
    845 			-k) updatefiles=1;;
    846 			-f) forcerebuild=1;;
    847 			-i) install=1;;
    848 			-u) upgrade=1;;
    849 			-o) downloadonly=1;;
    850 			-v) verbose=1;;
    851 			-*) msg "invalid option '$1'"; exit 1;;
    852 			*) pkg="$pkg $1";;
    853 		esac
    854 		shift
    855 	done
    856 }
    857 
    858 apkg_help() {
    859 	cat << EOF
    860 usage: ${0##*/} <option> <arg(s)>
    861 
    862 options:
    863   -i <pkg(s)>  install package(s)
    864   -I <pkg(s)>  install packages(s) with dependencies
    865   -d <pkg>     list <pkg> dependencies
    866   -D <pkg(s)>  list all dependencies
    867   -j <pkg>     list all dependents
    868   -u <pkg(s)>  upgrade package(s)
    869   -r <pkg(s)>  remove package(s)
    870   -t [pkg(s)]  trigger system cache/db updates
    871   -U           update system
    872   -f           force rebuild
    873   -o <pkg(s)>  download source
    874   -p <pkg>     print package path
    875   -g <pkg>     update package checksum
    876   -k <pkg>     update package files
    877   -l           list outdated packages
    878   -s <pattern> search packages
    879   -S <pattern> search files
    880   -v           be verbose
    881   -h           print this help message
    882   
    883 environment variables:
    884   APKG_ROOT          override default root (${APKG_ROOT:-/}) location
    885   APKG_CONF          override default $APKG_CONF location
    886   APKG_NOPROMPT      set the variable for non-interactive use
    887   APKG_LOG           set the variable for logging the output to a file
    888   
    889 EOF
    890 exit 0
    891 }
    892 
    893 main() {
    894 	parseopts "$@"
    895 	set -- $(updateopts "$@")
    896 	
    897 	if [ "$search" ]; then
    898 		pkg_search $@
    899 		exit 0
    900 	fi
    901 	
    902 	if [ "$allinstalled" ]; then
    903 		pkg_allinstalled $@
    904 		exit 0
    905 	fi
    906 	
    907 	for d in $APKG_PACKAGE_DIR $APKG_SOURCE_DIR $APKG_WORK_DIR $APKG_LOG_DIR; do
    908 		[ -d "$d" ] || { msg "Directory '$d' not exist"; exit 1; }
    909 		[ -w "$d" ] || { msg "Directory '$d' dont have write access"; exit 1; }
    910 	done
    911 	
    912 	if [ "$pkg" ]; then
    913 		for p in $pkg; do
    914 			[ "$(pkg_path "$p")" ] || {
    915 				msg "Package '$p' not found"
    916 				continue
    917 			}
    918 			(cd "$(pkg_path "$p")" && $APKG "$@") || exit 1
    919 		done
    920 		exit 0
    921 	fi
    922 
    923 	if [ ! -f ./abuild ]; then
    924 		msg "'abuild' not found."
    925 		exit 1
    926 	fi
    927 	
    928 	. ./abuild
    929 	[ "$name" ]    || die "name is empty"
    930 	[ "$version" ] || die "version is empty"
    931 	[ "$release" ] || die "release is empty"
    932 	[ "$name" = "${PWD##*/}" ] || {
    933 		msg "'name' should be same as package directory name (${PWD##*/})."
    934 		exit 1
    935 	}
    936 	
    937 	logfile="$APKG_LOG_DIR"/$name.log
    938 	packagefile="$APKG_PACKAGE_DIR"/$name#$version-$release.spm
    939 
    940 	if [ "$install" ] && [ -s "$SPM_PKGDB/${PWD##*/}" ]; then
    941 		msg "Package '${PWD##*/}' already installed."
    942 		exit 0
    943 	fi
    944 	
    945 	if [ "$upgrade" ] && [ ! -s "$SPM_PKGDB/${PWD##*/}" ]; then
    946 		msg "Package '${PWD##*/}' not installed."
    947 		exit 0
    948 	fi
    949 	
    950 	if [ "$updatecsum" ]; then
    951 		gencsum
    952 		exit 0
    953 	fi
    954 	
    955 	if [ "$downloadonly" ]; then
    956 		fetch_src
    957 		exit 0
    958 	fi
    959 	
    960 	if [ "$updatefiles" ]; then
    961 		pkg_updatefiles
    962 		exit 0
    963 	fi
    964 	
    965 	if [ "$(id -u)" != 0 ]; then
    966 		msg "Packages need to build as root. Aborted."
    967 		exit 1
    968 	fi
    969 	
    970 	if [ -f "$packagefile" ] && [ ! "$forcerebuild" ]; then
    971 		if [ ! "$install" ] && [ ! "$upgrade" ]; then
    972 			msg "Package '$packagefile' found."
    973 		fi
    974 	else	
    975 		if [ "$install" ] || [ "$upgrade" ]; then
    976 			# run preinstall script before build
    977 			runscript pre
    978 		fi
    979 		fetch_src
    980 		checksum_src
    981 		extract_src
    982 		[ "$APKG_LOG" ] && {
    983 			build_src 2>&1 | tee -- "$logfile"
    984 		} || {
    985 			build_src
    986 		}
    987 	fi	
    988 	
    989 	if [ "$install" ]; then
    990 		SPM_ROOT=${APKG_ROOT%/} spm -i "$packagefile" || exit $?
    991 	elif [ "$upgrade" ]; then
    992 		SPM_ROOT=${APKG_ROOT%/} spm -u "$packagefile" || exit $?
    993 	fi
    994 	
    995 	if [ "$install" ] || [ "$upgrade" ]; then
    996 		# run postinstall script after installed/upgraded
    997 		runscript post
    998 		[ "$APKG_ROOT" ] || pkg_trigger "$name"
    999 	fi
   1000 }
   1001 
   1002 umask 022
   1003 
   1004 export HERE="$PWD"
   1005 
   1006 APKG=$0
   1007 SPM_PKGDB="${APKG_ROOT%/}/var/lib/spm/db"
   1008 
   1009 # for apkg config, either override or default
   1010 APKG_CONF="${APKG_CONF:-/etc/apkg.conf}"
   1011 
   1012 ## NEED BETTER WAY TO DO THIS?
   1013 # environment override
   1014 O_APKG_REPO=$APKG_REPO
   1015 O_APKG_PACKAGE_DIR=$APKG_PACKAGE_DIR
   1016 O_APKG_SOURCE_DIR=$APKG_SOURCE_DIR
   1017 O_APKG_WORK_DIR=$APKG_WORK_DIR
   1018 O_APKG_LOG_DIR=$APKG_LOG_DIR
   1019 O_APKG_MASK=$APKG_MASK
   1020 
   1021 # default value
   1022 APKG_REPO="$PWD"
   1023 APKG_PACKAGE_DIR="$PWD"
   1024 APKG_SOURCE_DIR="$PWD"
   1025 APKG_WORK_DIR="$PWD"
   1026 APKG_LOG_DIR="$PWD"
   1027 
   1028 checksum_file="$HERE/.checksum"
   1029 
   1030 # source config
   1031 if [ -f "$APKG_CONF" ]; then
   1032 	. "$APKG_CONF"
   1033 fi
   1034 
   1035 # reset value, use override first, else either from config or use default
   1036 APKG_REPO=${O_APKG_REPO:-$APKG_REPO}
   1037 APKG_PACKAGE_DIR=${O_APKG_PACKAGE_DIR:-$APKG_PACKAGE_DIR}
   1038 APKG_SOURCE_DIR=${O_APKG_SOURCE_DIR:-$APKG_SOURCE_DIR}
   1039 APKG_WORK_DIR=${O_APKG_WORK_DIR:-$APKG_WORK_DIR}
   1040 APKG_LOG_DIR=${O_APKG_LOG_DIR:-$APKG_LOG_DIR}
   1041 APKG_MASK=${O_APKG_MASK:-$APKG_MASK}
   1042 
   1043 main "$@"
   1044 
   1045 exit 0