2 # Copyright (C) 2016-2019 Matias Fonzo <selk@dragora.org>
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # 0 = Successful completion
19 # 1 = Minor common errors (e.g: help usage, support not available)
20 # 2 = Command execution error
21 # 3 = Integrity check error for compressed files
22 # 4 = File empty, not regular, or expected
23 # 5 = Empty or not defined variable
24 # 6 = Package already installed
25 # 10 = Network manager error
32 "Qi - A practical and user-friendly package manager." \
34 "Usage: $PROGRAM [OPTION...] [FILE]..." \
37 " -b Build packages using recipes" \
38 " -c Create .tlz package from directory" \
39 " -d Delete packages" \
40 " -i Install packages" \
41 " -o Resolve build order through .order files" \
42 " -u Update packages (implies -i, -d with -p)" \
43 " -x Extract packages for debugging purposes" \
46 " -L Print default directory locations" \
47 " -N Don't read the configuration file" \
48 " -P <DIR> Package directory for (de)installations;" \
49 " only valid for -i, -d, or -u options" \
50 " -f Force package upgrade or force to proceed" \
52 " -t <DIR> Target directory for symbolic links;" \
53 " only valid for -i, -d, or -u options" \
54 " -k Keep (don't delete) srcdir or destdir" \
55 " Keep (don't delete) package directory" \
56 " this is for -b, -d or -u options" \
57 " -p Prune conflicts on package (de)installation" \
58 " -r Use the named directory as the root directory" \
59 " for installing, deleting, or upgrading packages." \
60 " The target directory, package directory will be" \
61 " relative to this specific directory" \
62 " -v Be verbose (a 2nd -v gives more)" \
64 "Options for 'build' mode (-b):" \
65 " -O <DIR> Where the produced packages are written" \
66 " -W <DIR> Where archives, patches, and recipes are expected" \
67 " -Z <DIR> Where (compressed) sources will be found" \
68 " -a Architecture to use [detected]" \
69 " -j Parallel jobs for the compiler" \
70 " -1 Increment release number (release + 1)" \
71 " -n Don't create a .tlz package" \
72 " -S Selects the option to skip completed recipes" \
75 " -h Display this help and exit" \
76 " -V Output version information" \
78 "Some influential environment variables:" \
79 " TMPDIR Temporary directory for sources" \
80 " QICFLAGS C compiler flags" \
81 " QICXXFLAGS C++ compiler flags" \
82 " QILDFLAGS Linker flags" \
84 "When FILE is -, read standard input." \
91 "$PROGRAM @VERSION@" \
92 "Copyright (C) 2016-2019 Matias Andres Fonzo." \
93 "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>" \
94 "This is free software: you are free to change and redistribute it." \
95 "There is NO WARRANTY, to the extent permitted by law."
100 printf "%s\n" "$@" 1>&2
109 echo "${PROGRAM}: cannot read ${1}: Permission denied" 1>&2
113 echo "${PROGRAM}: cannot access ${1}: No such file or directory" 1>&2
118 # Portable alternative to the file operator -nt (among shells)
121 if test -n "$(find $1 -prune -newer $2 -print)"
128 # Determine whether $2 matches pattern $1
145 if test $status -ne 0
147 echo "Return status = $status" 1>&2
148 exit ${1-2}; # If not given, defaults to 2
158 is_readable
"$HOME/.qirc" 2> /dev
/null
&& RCFILE
="$HOME/.qirc";
160 echo "Processing \`${RCFILE}' ..."
162 test -f "$RCFILE" ||
{
163 warn
"${RCFILE} is not a regular file."
168 while IFS
='=' read -r variable value
171 \
#* | "") # Ignore commented or blank lines
176 # Set variable name avoiding code execution
177 eval "$variable=\${value}"
188 # A recipe is any valid regular file, the current working directory
189 # has priority over the working tree (or where the recipes reside).
190 # The 'worktree' is the second place where to find a recipe. Also,
191 # we complete the possibility of using the directory name to invoke
192 # a recipe if it contains "recipe" as valid file name.
194 if test ! -f "$recipe"
196 if test -f "${recipe}/recipe"
198 recipe
="${recipe}/recipe"
199 elif test -f "${worktree}/recipes/${recipe}/recipe"
201 recipe
="${worktree}/recipes/${recipe}/recipe"
205 test -f "$recipe" ||
{
206 warn
"\`${recipe}' is not a regular file."
210 # Complain if the file name is not "recipe"
212 if test "${recipe##*/}" != recipe
214 warn
"\`${recipe}' is not a valid recipe name."
218 # Start preparations to import the recipe
220 # Separate the directory name from the file name,
221 # getting its absolute path and base name
223 CWD
=$
(CDPATH
= cd -P -- $
(dirname -- "$recipe") && printf "$PWD")
224 recipe
=$
(basename -- "$recipe")
226 # Check readability for load the recipe on success
228 is_readable
"${CWD}/$recipe" ||
exit 4
230 # Find target architecture if 'arch' is not set
233 arch
=$
(${CC:-cc} -dumpmachine 2> /dev
/null
) || arch
=unknown
234 arch
="${arch%%-*}" # Get the rid of target triplet.
237 # Re-create external directories
238 mkdir
-p -- "${worktree}/archive" \
239 "${worktree}/patches" \
240 "${worktree}/recipes" \
243 # Variables treatment for the current and next recipe.
245 # Unset special variables that can only be predefined on
246 # the recipe and not coming from ${sysconfdir}/qirc
248 unset srcdir destdir pkgname pkgversion program version release \
249 fetch description homepage license replace full_pkgname \
250 CFLAGS CXXFLAGS LDFLAGS
252 # The following variables must be saved and restored
253 save_arch
="${save_arch:=$arch}"
254 save_jobs
="${save_jobs:=$jobs}"
255 save_outdir
="${save_outdir:=$outdir}"
256 save_opt_nopkg
="${save_opt_nopkg:=$opt_nopkg}"
258 # Reset variable values in case of return
262 opt_nopkg
=$save_opt_nopkg
264 # The following variables cannot be redefined on the recipe
265 readonly worktree netget rsync
269 echo "{@} Building from ${CWD}/$recipe ..."
272 # Check for required variables
273 if test -z "$program"
275 warn
"${recipe}: The variable 'program' is not defined."
278 if test -z "$version"
280 warn
"${recipe}: The variable 'version' is not defined."
283 if test -z "$release"
285 warn
"${recipe}: The variable 'release' is not defined."
289 # Pre-settings before to start building
291 # Increment the release number if the option was given
292 if test "$opt_incr_release" = opt_incr_release
294 release
=$
(( release
+ 1 ))
297 # Allow the dot as definition for 'tardir'
298 if test "$tardir" = .
303 # Set default values for the following special variables
305 pkgname
="${pkgname:=$program}"
306 pkgversion
="${pkgversion:=$version}"
307 srcdir
="${srcdir:=${program}-$version}"
308 destdir
="${destdir:=${TMPDIR}/package-$pkgname}"
310 # Complete package name adding 'pkgversion-arch+release'
311 full_pkgname
="${full_pkgname:=$pkgname-${pkgversion}-${arch}+${release}}"
313 # If a package is going to be created, the existence of a
314 # previous build will be detected and reported. Under normal
315 # conditions the recipe is built as long as it is newer than
316 # the produced package, if not, we warn to the user about it.
317 # Rebuilding the package is possible (through the force ;-)
319 if test "$opt_nopkg" != opt_nopkg
&& \
320 { test "$opt_force" != opt_force
&& \
321 test -r "${outdir}/${full_pkgname}.tlz" ; }
323 if is_newer "${CWD}/$recipe" "${outdir}/${full_pkgname}.tlz
"
327 "The recipe is
more RECENT than the detected package
:" \
329 "$
( stat
-c "%y %n" "${CWD}/$recipe" )" \
330 "$
( stat
-c "%y %n" "${outdir}/${full_pkgname}.tlz" )" \
332 " This recipe will be processed ...
" \
334 elif test -e "${CWD}/post-install
" && \
335 is_newer "${CWD}/post-install
" "${CWD}/$recipe"
339 "The post-install
script is
more RECENT than the recipe
:" \
341 "$
( stat
-c "%y %n" "${CWD}/post-install" )" \
342 "$
( stat
-c "%y %n" "${CWD}/$recipe" )" \
344 " The recipe will be re-processed ...
" \
346 touch "${CWD}/$recipe"
347 elif test "$opt_skipqsts" = opt_skipqsts
349 warn "Recipe
for '${full_pkgname}.tlz': Ignored.
" ""
354 "This recipe ALREADY produced a package
:" \
355 "$
( stat
-c "%y %n" "${outdir}/${full_pkgname}.tlz" )" \
357 "The recipe is still OLDER than the produced package
:" \
358 "$
( stat
-c "%y %n" "${CWD}/$recipe" )" \
360 " Probably nothing has changed.
" \
363 # In non-interactive mode, the user is asked about
364 # rebuilding the package. In interactive mode,
365 # the user need to pass the option explicitly
369 "Do you want to rebuild this package?
\n" \
370 "1) Yes
, built it
\n" \
371 "2) No
, skipt it
[default
]\n" \
372 "3) Resume
, skipping completed recipes
\n" \
373 "Choose an option number
: " > /dev/tty
374 IFS= read -r ANSWER < /dev/tty || exit 2;
377 echo "$ANSWER" > /dev/tty
382 echo "Building UNPROCESSED
/MODIFIED recipes ...
" > /dev/tty
384 opt_skipqsts=opt_skipqsts
385 readonly opt_skipqsts
390 echo "Recipe
for '${full_pkgname}.tlz': Cancelled.
" > /dev/tty
396 warn "Use the
-f option to re-process
${CWD}/$recipe.
" ""
402 # Fetch remote sources
404 echo "Fetching remote sources
if needed ...
"
409 _source="${origin##*/}"
411 echo "Looking
for \"$_source\" ...
"
413 echo "Verifying checksum
file \"${_source}.sha256
\" from
'${tardir}'"
414 if test -e "${tardir}/${_source}.sha256
"
416 ( cd -- "$tardir" && sha256sum - ) < "${tardir}/${_source}.sha256
"
420 warn "${_source}.sha256
: Checksum
file does not exist
, yet.
"
423 # Download source or resume if allowed
425 if test ! -e "${tardir}/$_source"
427 warn " Can
't find $_source in ${tardir};" \
428 "attempting to get it from ${origin%/*} ..."
434 cd -- "$tardir" && $rsync $origin || exit $?
435 sha256sum $_source > ${_source}.sha256
436 ); chkstatus_or_exit 10
440 cd -- "$tardir" && $netget $origin || exit $?
441 sha256sum $_source > ${_source}.sha256
442 ); chkstatus_or_exit 10
445 warn "${PROGRAM}: Unrecognized protocol for ${origin}."
451 warn "The variable 'fetch
' is empty."
454 # Prepare special directories for build the source,
455 # the destination and the output of the package
457 echo "Preparing directories ..."
459 if test -d "${TMPDIR}/$srcdir" && test -z "$keep_srcdir"
461 rm -rf -- "${TMPDIR}/$srcdir" || chkstatus_or_exit
462 echo "removed directory: '${TMPDIR}/$srcdir'"
465 if test -d "$destdir"
467 rm -rf -- "$destdir" || chkstatus_or_exit
468 echo "removed directory: '$destdir'"
470 mkdir -p -- "$destdir" || chkstatus_or_exit
471 echo "mkdir: created directory '$destdir'"
473 if test ! -d "$outdir"
475 mkdir -p -- "$outdir" || chkstatus_or_exit
476 echo "mkdir: created directory '$outdir'"
479 echo "Entering to 'TMPDIR
': $TMPDIR ..."
480 cd -- "$TMPDIR" || chkstatus_or_exit
482 # Set trap before to run the build() function in order
483 # to catch the return status, exit code 2 if fails
485 trap 'chkstatus_or_exit
2' EXIT HUP INT QUIT ABRT TERM
487 # Determine if the debugging indicators of the shell should be
488 # retained, assuming that it has been previously passed
490 _xtrace_flag_is_set=xtrace_flag_is_set ;;
493 echo "Running build() ..."
497 # Turn off possible shell flags coming from the recipe
500 if test "$_xtrace_flag_is_set" != xtrace_flag_is_set
505 # Reset given signals
506 trap - EXIT HUP INT QUIT ABRT TERM
508 # If 'destdir
' is empty, the package won't be created
509 if rmdir -- "$destdir" 2> /dev
/null
511 warn
"The package \"${full_pkgname}.tlz\" won't be created. 'destdir' is empty."
515 # Create (make) the package
517 if test "$opt_nopkg" != opt_nopkg
519 # Edit the recipe when 'release' is incremented
520 if test "$opt_incr_release" = opt_incr_release
522 echo ",s/^\(release\)=.*/\1=${release}/"$
'\nw' | \
523 ed
"${CWD}/$recipe" || chkstatus_or_exit
526 mkdir
-p -- "${destdir}/var/lib/qi" || chkstatus_or_exit
528 # Include a recipe copy into the package
529 cp -p "${CWD}/$recipe" \
530 "${destdir}/var/lib/qi/${full_pkgname}.recipe" && \
531 chmod 644 "${destdir}/var/lib/qi/${full_pkgname}.recipe" || chkstatus_or_exit
533 # Detect post-install script for inclusion
535 if test -f "${CWD}/post-install"
537 echo "${CWD}/post-install: Detected."
538 cp -p "${CWD}/post-install" \
539 "${destdir}/var/lib/qi/${full_pkgname}.sh" && \
540 chmod 644 "${destdir}/var/lib/qi/${full_pkgname}.sh" || chkstatus_or_exit
543 # Detect declared package names for later replacement
545 if test -n "$replace"
548 "The following package names has been declared for replacement:" \
551 rm -f "${destdir}/var/lib/qi/${full_pkgname}.replace"
554 echo "$replace" >> "${destdir}/var/lib/qi/${full_pkgname}.replace"
559 # Create meta file for the package information
560 echo "Creating meta file ${full_pkgname}.tlz.txt ..."
561 do_meta
> "${outdir}/${full_pkgname}.tlz.txt" || chkstatus_or_exit
563 # Make a copy of it for the database
564 cp -p "${outdir}/${full_pkgname}.tlz.txt" \
565 "${destdir}/var/lib/qi/${full_pkgname}.txt" || chkstatus_or_exit
567 # Produce the package
568 cd -- "$destdir" && create_mode
"${outdir}/${full_pkgname}.tlz"
571 # Back to the current working directory
572 cd -- "$CWD" || chkstatus_or_exit
574 # Delete 'srcdir' or 'destdir' if -k is not given
575 if test "$opt_keep" != opt_keep
577 echo "Deleting temporary directories ..."
579 srcdir
="${srcdir%%/*}" # Directory name without parents.
581 if test -r "${TMPDIR}/$srcdir"
583 if test -z "$keep_srcdir"
585 rm -rf -- "${TMPDIR}/$srcdir" || chkstatus_or_exit
586 echo "removed directory: '${TMPDIR}/${srcdir}'"
588 warn
"The variable 'keep_srcdir' is set:" \
589 "'${TMPDIR}/${srcdir}' will not be deleted."
593 if test -r "$destdir"
595 rm -rf -- "$destdir" || chkstatus_or_exit
596 echo "removed directory: '$destdir'"
600 # Install or update the package if -i or -u was passed
601 if test "$opt_nopkg" != opt_nopkg
603 if test "$opt_install" = opt_install
605 install_mode
"${outdir}/${full_pkgname}.tlz"
606 elif test "$opt_update" = opt_update
608 upgrade_mode
"${outdir}/${full_pkgname}.tlz"
613 echo "All done for ${CWD}/${recipe}."
619 directory
=$
(dirname -- "$1")
620 name
=$
(basename -- "$1")
622 # Perform sanity checks
624 is_readable
"$directory" ||
exit 4
626 # Check again to find out if it is a valid directory
627 test -d "$directory" ||
{
628 warn
"Package directory '$name' does not exist."
632 test "$directory" = .
&& {
633 warn
"Cannot create package on current working directory."
637 test "$name" = "${name%.tlz}" && {
639 "Package format '$name' not supported." \
640 "It should be \`name-version-architecture+release.tlz'"
644 echo "{#} Creating package $name at $directory ..."
646 ( umask 022 ; tar cvf
- .
/* | lzip
-9cvv ) > "${directory}/$name"
649 echo "Package created \"${directory}/${name}\"."
651 echo "${directory}/$name: Creating SHA256 checksum ..."
652 ( cd -- "$directory" && sha256sum
$name > ${name}.sha256
)
654 # Remove used variables
660 expunge
="${packagedir}/$(basename -- $1 .tlz)"
662 echo "<<< Deleting package $rootdir${expunge} ..."
664 # Complain if the package directory does not exist
666 test -d "$rootdir${expunge}" ||
{
667 warn
"Package directory '$rootdir${expunge}' does not exist."
671 # Complain if the package directory cannot be well-read
673 is_readable
"$rootdir${expunge}" ||
exit 4
675 # Remove package from Graft control
677 # Scan for possible conflicts, stop if arise
678 if test "$opt_prune" != opt_prune
680 echo "Checking for possible conflicts ..."
681 if graft
-d -n $graft_r -t "$targetdir" "$expunge" 2>&1 | \
685 " A conflict occurred during uninstallation;" \
686 "Unless the -p option is given, this package will be PRESERVED."
691 # Ignore some signals up to completing the deinstallation
692 trap "" HUP INT QUIT ABRT TERM
694 # Remove objects (files, links or directories) from the target
695 # directory that are in conflict with the package directory
697 echo "Pruning any conflict ..."
698 graft
-p -D -u $graft_r -t "$targetdir" "$expunge"
701 echo "Disabling links ..."
702 graft
-d -D -u $graft_v $graft_r -t "$targetdir" "$expunge"
705 # Delete package directory
706 if test "$opt_keep" != opt_keep
708 echo "Deleting package directory, if present ..."
710 if test -d "${rootdir}$expunge"
712 rm -rf -- "${rootdir}$expunge" || chkstatus_or_exit
713 echo "removed directory: '${rootdir}$expunge'"
717 # Reset given signals
718 trap - HUP INT QUIT ABRT TERM
720 # Remove used variables
726 # Complain if the package cannot be well-read
728 is_readable
"$1" ||
exit 4
730 # Complain if the package does not end in .tlz
732 if ! fnmatch
'*.tlz' "$1"
734 warn
"\`${1}' does not end in .tlz"
738 # Make preparations to install the package
740 echo ">>> Installing package $1 ..."
743 name
=$
(basename -- "$1" .tlz
)
745 echo "Checking tarball integrity ..."
746 tar -tf "$1" > /dev
/null
749 # Create package directory using 'name'
750 if ! test -d "$rootdir${packagedir}/$name"
752 mkdir
-p -- "$rootdir${packagedir}/$name" || chkstatus_or_exit
753 echo "mkdir: created directory '$rootdir${packagedir}/$name'"
756 # Scan for possible conflicts, stop if arise
757 if test "$opt_prune" != opt_prune
759 echo "Checking for possible conflicts ..."
760 if graft
-i -n $graft_r -t "$targetdir" "${packagedir}/$name" 2>&1 | \
764 " A conflict occurred during installation;" \
765 "Unless the -p option is given, this package won't be LINKED."
770 # Ignore some signals up to completing the installation
771 trap "" HUP INT QUIT ABRT TERM
773 echo "Decompressing $1 ..."
774 ( cd -- "$rootdir${packagedir}/$name" && lzip
-cd - |
tar xpf
- ) < "$1"
777 # Transite package to Graft control
779 # Remove objects (files, links or directories) from the target
780 # directory that are in conflict with the package directory
781 echo "Pruning any conflict ..."
782 graft
-p -D -u $graft_r -t "$targetdir" "${packagedir}/$name"
785 echo "Enabling symbolic links ..."
786 graft
-i -P $graft_v $graft_r -t "$targetdir" "${packagedir}/$name"
789 # Avoid unnecessary runs coming from the upgrade_mode(),
790 # this is when the incoming package is **pre-installed**
792 if test "$_isUpgrade" != _isUpgrade.on
794 # Show package description
795 if test -r "$rootdir${packagedir}/${name}/var/lib/qi/${name}.txt"
797 grep '^#' "$rootdir${packagedir}/${name}/var/lib/qi/${name}.txt"
798 elif test -r "${1}.txt"
800 # From external meta file (current directory)
803 warn
"Description file not found for '$name'."
806 # Check and run the post-install script if exist
807 if test -r "$rootdir${packagedir}/${name}/var/lib/qi/${name}.sh"
809 echo "Running post-install script for \`${name}' ..."
811 # Rely on 'targetdir' if 'rootdir' is empty
812 cd -- "${rootdir:-$targetdir}"/ && \
813 .
"$rootdir${packagedir}/${name}/var/lib/qi/${name}.sh"
817 # Check if there are declared packages for replacement
818 if test -r "$rootdir${packagedir}/${name}/var/lib/qi/${name}.replace"
822 for replace
in "$rootdir${packagedir}/$(pkgbase $line)"-*
824 if ! test -e "$replace"
826 warn
"${replace}: Declared package does not exist. (ignored)"
830 replace
="${replace##*/}"
832 # The search for the package to be replaced cannot
833 # be the same to the incoming package, even to the
834 # temporary location coming from the upgrade_mode()
835 if test "$replace" = "$name" ||
test "$replace" = "${PRVLOC##*/}"
840 warn
"WARNING: Replacing package \`${replace}' ..."
842 # Since the links belongs to the new package, only
843 # those which are not in conflict can be deleted.
844 # To complete, we will remove the package directory
846 graft
-d -D -u $graft_r \
847 -t "$targetdir" "$replace" > /dev
/null
2>&1
849 rm -rf -- "$rootdir${packagedir}/$replace"
851 done < "$rootdir${packagedir}/${name}/var/lib/qi/${name}.replace"
856 # Reset given signals
857 trap - HUP INT QUIT ABRT TERM
859 # Remove used variables
864 # Complain if the file cannot be well-read
866 is_readable
"$1" ||
exit 4
868 # Complain if the file does not end in .order
870 if ! fnmatch
'*.order' "$1"
872 warn
"\`${1}' does not end in .order"
876 # Get a clean list of the file while prints its content in reverse order,
877 # lines containing: colons, comments, parentheses, end of line, and blank
878 # lines, are removed. The parentheses are used to insert a reference.
879 # The last `awk' in the pipe: removes nonconsecutive lines, duplicate.
881 '{ gsub( /:|^#(.*)$|\([^)]*)|^$/,"" ); for( i=NF; i > 0; i-- ) print $i }' \
882 "$1" |
awk '!s[$0]++'
887 # Complain if the package is not a regular file
890 warn
"\`${1}' is not a regular file."
895 incoming
=$
(basename -- "$1" .tlz
)
897 echo "<>> Upgrading package $incoming ..."
899 if test "$opt_force" != opt_force
&& test -e "${packagedir}/$incoming"
902 " The package to be updated already exist;" \
903 "Unless the -f option is given, this package won't be UPGRADED."
907 # Check for packages declared in the black list only for installation
909 for item
in $blacklist
915 "* The incoming package will be installed instead of being updated." \
916 "* This may be crucial for the correct functioning of \`${PROGRAM}'." \
918 opt_prune
=opt_prune install_mode
"$1"
924 # Prepare the package to install it in a temporary location
926 # Set random directory using packagedir as prefix and 'incoming' as suffix
927 PRVLOC
=$
(mktemp
-dp "$rootdir${packagedir}" ${incoming}.XXXXXXXXXXXX
) ||
exit 2
929 # Pre-install the package in the custom 'packagedir'
931 save_packagedir
="$packagedir"
934 echo "Pre-installing package using temporary location ..."
935 opt_prune
=opt_prune
# Turn on prune operation.
936 _isUpgrade
=_isUpgrade.on install_mode
"$1" > /dev
/null
937 _isUpgrade
=_isUpgrade.off
939 # Restore variable before looking for old packages
940 packagedir
=$save_packagedir
941 unset save_packagedir
943 echo "Looking for installations under the same name ..."
944 for long_name
in "$rootdir${packagedir}/$(pkgbase $incoming)"*
946 found
="${long_name##*/}"
948 # The search for the package to be deleted
949 # cannot be the same to the temporary location
950 test "$long_name" = "$PRVLOC" && continue;
952 fnmatch
"$(pkgbase $found)*" "$incoming" ||
continue;
953 echo "${long_name}: Detected."
955 # A package directory is preserved if -k is given
956 delete_mode
"$found" > /dev
/null
958 unset long_name found
960 # Re-install the package removing the temporary location
963 opt_prune
=opt_prune.off
# Turn off prune operation.
965 echo "Deleting temporary location ..."
966 rm -rf -- "$PRVLOC" || chkstatus_or_exit
967 echo "removed directory: '$PRVLOC'"
970 echo "Successful upgrade to '${incoming}'."
972 # Remove remaining variables
973 unset incoming PRVLOC
978 # Perform sanity checks before package extraction
980 is_readable
"$1" ||
exit 4
983 warn
"\`${1}' is not a regular file."
987 # Preparations to extract the package
989 name
=$
(basename -- "$1" .tlz
)
991 # Set random directory using 'name' as prefix
992 PRVDIR
="${TMPDIR}/${name}.${RANDOM-0}$$"
994 # Trap to remove 'PRVDIR' on disruptions
995 trap "rm -rf -- $PRVDIR" HUP INT ABRT TERM
997 # Create 'PRVDIR' removing access for all but user
998 ( umask 077 ; mkdir
-- $PRVDIR )
999 mkdir
-p -m 700 -- $PRVDIR
1001 echo "Extracting package $name ..."
1002 ( umask 000 ; cd -- $PRVDIR && lzip
-cd - |
tar xpvf
- ) < "$1"
1005 # Try to remove (empty) 'PRVDIR' on failure
1009 echo "$name has been extracted on $PRVDIR"
1011 # Reset given signals
1012 trap - HUP INT ABRT TERM
1014 # Remove used variables
1018 #### Extra functions used in the modes
1022 string
=$
(basename -- "$1" .tlz
)
1024 # Match cases to print the package name.
1026 # We will take into account the four segments removing
1027 # the last two to print the package (long) name
1030 echo "${string%-*-*}"
1046 tar tf
"$file" > /dev
/null
&& \
1050 *.
tar.gz |
*.tgz |
*.
tar.Z
)
1051 gzip -cd "$file" |
tar tf
- > /dev
/null
&& \
1052 gzip -cd "$file" |
tar xpf
-
1055 *.
tar.bz2 |
*.tbz2 |
*.tbz
)
1056 bzip2 -cd "$file" |
tar tf
- > /dev
/null
&& \
1057 bzip2 -cd "$file" |
tar xpf
-
1061 lzip
-cd "$file" |
tar tf
- > /dev
/null
&& \
1062 lzip
-cd "$file" |
tar xpf
-
1066 xz
-cd "$file" |
tar tf
- > /dev
/null
&& \
1067 xz
-cd "$file" |
tar xpf
-
1071 unzip -t "$file" > /dev
/null
&& \
1072 unzip "$file" > /dev
/null
1076 gzip -t "$file" && \
1077 gzip -cd "$file" > "$(basename -- $file .gz)"
1081 gzip -t "$file" && \
1082 gzip -cd "$file" > "$(basename -- $file .Z)"
1086 bzip2 -t "$file" && \
1087 bzip2 -cd "$file" > "$(basename -- $file .bz2)"
1091 lzip
-t "$file" && \
1092 lzip
-cd "$file" > "$(basename -- $file .lz)"
1097 xz
-cd "$file" > "$(basename -- $file .xz)"
1101 warn
"${PROGRAM}: cannot unpack ${file}: Unsupported extension"
1110 # Extract information from the recipe to create the meta file.
1112 # The package description is pre-formatted in 78 columns,
1113 # the '#' character and a space is added as prefix to conform
1114 # 80 columns in total
1117 $(echo "$description" | fold -w 78 | awk '$0="# " $0')
1119 QICFLAGS="$QICFLAGS"
1120 QICXXFLAGS="$QICXXFLAGS"
1121 QILDFLAGS="$QILDFLAGS"
1125 blurb="$(echo "$description" | sed -e '/^$/d;2q')"
1126 homepage="$homepage"
1137 packagedir
=@PACKAGEDIR@
1138 targetdir
=@TARGETDIR@
1139 blacklist
="perl graft tar plzip musl glibc"
1141 RCFILE
=@SYSCONFDIR@
/qirc
1142 opt_install
=opt_install.off
1143 opt_update
=opt_update.off
1144 opt_force
=opt_force.off
1145 opt_keep
=opt_keep.off
1146 opt_incr_release
=opt_incr_release.off
1147 opt_skipqsts
=opt_skipqsts.off
1148 opt_nopkg
=opt_nopkg.off
1149 opt_prune
=opt_prune.off
1156 _isUpgrade
=_isUpgrade.off
1157 TMPDIR
="${TMPDIR:=/usr/src/qi/build}"
1158 QICFLAGS
="${QICFLAGS:=-g0 -Os}"
1159 QICXXFLAGS
="${QICXXFLAGS:=$QICFLAGS}"
1160 QILDFLAGS
="${QILDFLAGS:=-s}"
1161 worktree
=/usr
/src
/qi
1162 tardir
=${worktree}/sources
1163 outdir
=/var
/cache
/qi
/packages
1164 netget
="wget -c -w1 -t3 --no-check-certificate"
1165 rsync
="rsync -v -a -L -z -i --progress"
1166 configure_args
="--prefix=@PREFIX@ --libexecdir=@LIBEXECDIR@ --bindir=@BINDIR@ --sbindir=@SBINDIR@ --sysconfdir=@SYSCONFDIR@ --localstatedir=@LOCALSTATEDIR@"
1171 # Store (default) directory locations
1172 QI_TARGETDIR
=$targetdir
1173 QI_PACKAGEDIR
=$packagedir
1174 QI_WORKTREE
=$worktree
1180 while getopts :bcdiouxLNP
:t
:fkvO
:W
:Z
:a
:j
:1nSpr
:hV name
1203 if test "$mode" = build_mode
1205 opt_install
=opt_install
1217 if test "$mode" = build_mode
1219 opt_update
=opt_update
1227 "QI_TARGETDIR=$QI_TARGETDIR" \
1228 "QI_PACKAGEDIR=$QI_PACKAGEDIR" \
1229 "QI_WORKTREE=$QI_WORKTREE" \
1230 "QI_TARDIR=$QI_TARDIR" \
1231 "QI_OUTDIR=$QI_OUTDIR"
1238 packagedir
="$OPTARG"
1250 verbose
=$
(( verbose
+ 1 ))
1268 opt_incr_release
=opt_incr_release
1274 opt_skipqsts
=opt_skipqsts
1291 warn
"Option '-${OPTARG}' requires an argument"
1296 warn
"Illegal option -- '-${OPTARG}'"
1302 shift $
(( OPTIND
- 1 ))
1310 # Program sanity check
1311 for need
in awk basename bzip2 chmod cp dirname find fold graft
grep \
1312 lzip mkdir mktemp
rm rmdir sed sha256sum stat
tar
1314 if ! type $need 1> /dev
/null
2> /dev
/null
1316 warn
"${PROGRAM}: cannot operate without ${need}(1): Check your PATH"
1322 # Determine verbosity level/flag
1324 if test "$verbose" -gt 1
1329 # Read standard input if FILE is -, or when FILE
1330 # is not connected to a terminal.
1332 if test "$1" = - ||
test ! -t 0
1334 # Unset positional parameters setting $# to zero
1337 # Assign remaining arguments to the positional parameters
1340 set -- "$@" "$input"
1344 # We need at least one operating mode
1351 umask 022; # Remove write permission for group and other.
1353 # Validate 'rootdir' directory
1355 if test -n "$rootdir"
1357 if test -d "$rootdir" && test "$rootdir" != /
1359 # Remove slash from the end
1360 rootdir
="${rootdir%/}"
1362 # A workaround for graft-2.13+. The specified directory is
1363 # relative to the log file, we prepend it inside the rootdir
1365 eval "$(graft -L)" ; GRAFT_LOGFILE
="${GRAFT_LOGFILE:=/var/log/graft}"
1366 mkdir
-p -- "$rootdir$(dirname -- $GRAFT_LOGFILE)" || chkstatus_or_exit
1368 # Compose 'rootdir' and log file option to be used with graft(1)
1369 graft_r
="-r $rootdir -l $GRAFT_LOGFILE"
1371 # Unset variables coming from eval
1372 unset GRAFT_PERL GRAFT_LOGFILE GRAFT_TARGETDIR GRAFT_PACKAGEDIR
1374 warn
"${PROGRAM}: \`${rootdir}' is not a qualified root directory"
1380 # Ensure 'TMPDIR' creation to prefix temporary files
1382 if test ! -d "$TMPDIR"
1384 mkdir
-p -- "$TMPDIR" || chkstatus_or_exit
1388 # Process each package or recipe provided on the command-line