diff options
58 files changed, 979 insertions, 813 deletions
diff --git a/Makefile.am b/Makefile.am index 7b53fd0e..28f7f8f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ dist_pkgdata_DATA = \ check-local: test-pacman test-pacsort test-vercmp test-parseopts test-pacman: test/pacman src/pacman - LC_ALL=C $(PYTHON) $(top_srcdir)/test/pacman/pactest.py --debug=1 \ + $(PYTHON) $(top_srcdir)/test/pacman/pactest.py --debug=1 \ --test $(top_srcdir)/test/pacman/tests/*.py \ --scriptlet-shell $(SCRIPTLET_SHELL) \ --ldconfig $(LDCONFIG) \ diff --git a/configure.ac b/configure.ac index f33cc5d7..0908256f 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,11 @@ AC_ARG_WITH(buildscript, AS_HELP_STRING([--with-buildscript=name], [set the build script name used by makepkg]), [BUILDSCRIPT=$withval], [BUILDSCRIPT=PKGBUILD]) +# Help line for buildscript filename +AC_ARG_WITH(makepkg-template-dir, + AS_HELP_STRING([--with-makepkg-template-dir=name], [set the template dir used by makepkg-template]), + [TEMPLATE_DIR=$withval], [TEMPLATE_DIR=/usr/share/makepkg-template]) + # Help line for debug package suffix AC_ARG_WITH(debug-suffix, AS_HELP_STRING([--with-debug-suffix=name], [set the suffix for split debugging symbol packages used by makepkg]), @@ -166,6 +171,16 @@ AC_PROG_INSTALL AC_CHECK_PROGS([PYTHON], [python2.7 python2.6 python2.5 python2 python], [false]) AC_PATH_PROGS([BASH_SHELL], [bash bash4], [false]) +# check for perl 5.10.1 (needed by makepkg-template) +AC_PATH_PROG([PERL],[perl]) +AC_DEFUN([AX_PROG_PERL_VERSION], + [AC_CACHE_CHECK([for Perl version $1 or later], [ax_cv_prog_perl_version], + [AS_IF(["$PERL" -e 'require v$1;' >/dev/null 2>&1], + [ax_cv_prog_perl_version=yes], + [ax_cv_prog_perl_version=no])]) + AS_IF([test x"$ax_cv_prog_perl_version" = xyes], [$2], [$3])]) +AX_PROG_PERL_VERSION([5.10.1], [], [AC_MSG_ERROR([perl is too old])]) + AS_IF([test "x$BASH_SHELL" = "xfalse"], AC_MSG_WARN([*** bash >= 4.1.0 is required for pacman scripts]), [bash_version_major=`$BASH_SHELL -c 'echo "${BASH_VERSINFO[[0]]}"'` @@ -457,6 +472,9 @@ AC_DEFINE_UNQUOTED([SRCEXT], "$SRCEXT", [The file extension used by pacman sourc # Set makepkg build script name AC_SUBST(BUILDSCRIPT) AC_DEFINE_UNQUOTED([BUILDSCRIPT], "$BUILDSCRIPT", [The build script name used by makepkg]) +# Set makepkg-template template directory +AC_SUBST(TEMPLATE_DIR) +AC_DEFINE_UNQUOTED([TEMPLATE_DIR], "$TEMPLATE_DIR", [The template directory used by makepkg-teplate]) # Set makepkg split debugging symbol package suffix AC_SUBST(DEBUGSUFFIX) AC_DEFINE_UNQUOTED([DEBUGSUFFIX], "$DEBUGSUFFIX", [The suffix for debugging symbol packages used by makepkg]) @@ -524,6 +542,7 @@ ${PACKAGE_NAME}: package extension : ${PKGEXT} source pkg extension : ${SRCEXT} build script name : ${BUILDSCRIPT} + template directory : ${TEMPLATE_DIR} Compilation options: Use libcurl : ${have_libcurl} diff --git a/contrib/bash_completion.in b/contrib/bash_completion.in index 28981ae4..519aa6dc 100644 --- a/contrib/bash_completion.in +++ b/contrib/bash_completion.in @@ -77,7 +77,7 @@ _makepkg() { if [[ $cur = -* && ! $prev =~ ^-(-(config|help)$|\w*[Chp]) ]]; then opts=('allsource asdeps asroot check clean config force geninteg help holdver ignorearch install key log needed nobuild nocheck nocolor noconfirm nodeps noextract - noprogressbar nosign pkg repackage rmdeps sign skipchecksums skipinteg + noprepare noprogressbar nosign pkg repackage rmdeps sign skipchecksums skipinteg skippgpcheck source syncdeps verifysource version' 'A L R S c d e f g h i m o p r s') _arch_ptr2comp opts diff --git a/contrib/paccache.sh.in b/contrib/paccache.sh.in index a9c6524f..2bbe7266 100644 --- a/contrib/paccache.sh.in +++ b/contrib/paccache.sh.in @@ -159,22 +159,25 @@ options to help control how much, and what, is deleted from any directory containing pacman package tarballs. Operations: - -d, --dryrun perform a dry run, only finding candidate packages. - -m, --move <dir> move candidate packages to 'movedir'. - -r, --remove remove candidate packages. + -d, --dryrun perform a dry run, only finding candidate packages. + -m, --move <dir> move candidate packages to 'movedir'. + -r, --remove remove candidate packages. Options: - -a, --arch <arch> scan for 'arch' (default: all architectures). - -c, --cachedir <dir> scan 'cachedir' for packages (default: @localstatedir@/cache/pacman/pkg). - -f, --force apply force to mv(1) and rm(1) operations. - -h, --help display this help message and exit. - -i, --ignore <pkgs> ignore 'pkgs', comma separated. Alternatively, specify '-' to - read package names from stdin, newline delimited. - -k, --keep <num> keep 'num' of each package in 'cachedir' (default: 3). - --nocolor remove color from output. - -u, --uninstalled target uninstalled packages. - -v, --verbose increase verbosity. specify up to 3 times. - -z, --null use null delimiters for candidate names (only with -v and -vv) + -a, --arch <arch> scan for 'arch' (default: all architectures). + -c, --cachedir <dir> scan 'cachedir' for packages. + (default: @localstatedir@/cache/pacman/pkg). + -f, --force apply force to mv(1) and rm(1) operations. + -h, --help display this help message and exit. + -i, --ignore <pkgs> ignore 'pkgs', comma separated. Alternatively, specify + '-' to read package names from stdin, newline + delimited. + -k, --keep <num> keep 'num' of each package in 'cachedir' (default: 3). + --nocolor remove color from output. + -u, --uninstalled target uninstalled packages. + -v, --verbose increase verbosity. specify up to 3 times. + -z, --null use null delimiters for candidate names (only with -v + and -vv). EOF } diff --git a/contrib/zsh_completion.in b/contrib/zsh_completion.in index c150144c..67aa40a7 100644 --- a/contrib/zsh_completion.in +++ b/contrib/zsh_completion.in @@ -589,6 +589,7 @@ _makepkg_longopts=( '--holdver[Prevent automatic version bumping for development PKGBUILDs]' '--key[Specify key to use for gpg signing instead of the default]: :_keys' '--nocheck[Do not run the check() function in the PKGBUILD]' + '--noprepare[Do not run the prepare() function in the PKGBUILD]' '--nosign[Do not create a signature for the package]' '--pkg[Only build listed packages from a split package]' '--sign[Sign the resulting package with gpg]' diff --git a/doc/.gitignore b/doc/.gitignore index a96ddb30..ad496ce0 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,6 +1,7 @@ PKGBUILD.5 libalpm.3 makepkg.8 +makepkg-template.1 makepkg.conf.5 pacman.8 pacman-key.8 diff --git a/doc/Makefile.am b/doc/Makefile.am index bcb05b74..cb012551 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -6,6 +6,7 @@ ASCIIDOC_MANS = \ pacman.8 \ makepkg.8 \ + makepkg-template.1 \ repo-add.8 \ vercmp.8 \ pkgdelta.8 \ @@ -21,6 +22,7 @@ DOXYGEN_MANS = $(wildcard man3/*.3) HTML_MANPAGES = \ pacman.8.html \ makepkg.8.html \ + makepkg-template.1.html \ repo-add.8.html \ vercmp.8.html \ pkgdelta.8.html \ @@ -46,6 +48,7 @@ EXTRA_DIST = \ asciidoc-override.css \ pacman.8.txt \ makepkg.8.txt \ + makepkg-template.1.txt \ repo-add.8.txt \ vercmp.8.txt \ pkgdelta.8.txt \ @@ -147,6 +150,7 @@ $(HTML_OTHER): asciidoc.conf Makefile.am # Dependency rules pacman.8 pacman.8.html: pacman.8.txt makepkg.8 makepkg.8.html: makepkg.8.txt +makepkg-template.1 makepkg-template.1.html: makepkg-template.1.txt repo-add.8 repo-add.8.html: repo-add.8.txt vercmp.8 vercmp.8.html: vercmp.8.txt pkgdelta.8 pkgdelta.8.html: pkgdelta.8.txt diff --git a/doc/PKGBUILD-example.txt b/doc/PKGBUILD-example.txt index 9ab5dff9..910fd068 100644 --- a/doc/PKGBUILD-example.txt +++ b/doc/PKGBUILD-example.txt @@ -1,24 +1,27 @@ # Maintainer: Joe User <joe.user@example.com> pkgname=patch -pkgver=2.5.4 -pkgrel=3 +pkgver=2.7.1 +pkgrel=1 pkgdesc="A utility to apply patch files to original sources" arch=('i686' 'x86_64') url="https://www.gnu.org/software/patch/patch.html" license=('GPL') groups=('base-devel') -depends=('glibc' 'ed') -source=(ftp://ftp.gnu.org/gnu/$pkgname/$pkgname-$pkgver.tar.gz) -md5sums=('ee5ae84d115f051d87fcaaef3b4ae782') +depends=('glibc') +makedepends=('ed') +optdepends=('ed: for "patch -e" functionality') +source=("ftp://ftp.gnu.org/gnu/$pkgname/$pkgname-$pkgver.tar.xz"{,.sig}) +md5sums=('e9ae5393426d3ad783a300a338c09b72' + 'SKIP') build() { - cd "$srcdir"/$pkgname-$pkgver - ./configure --prefix=/usr - make + cd "$srcdir/$pkgname-$pkgver" + ./configure --prefix=/usr + make } package() { - cd "$srcdir"/$pkgname-$pkgver - make prefix="$pkgdir"/usr install + cd "$srcdir/$pkgname-$pkgver" + make DESTDIR="$pkgdir/" install } diff --git a/doc/PKGBUILD.5.txt b/doc/PKGBUILD.5.txt index e78a8e5a..1b229aaf 100644 --- a/doc/PKGBUILD.5.txt +++ b/doc/PKGBUILD.5.txt @@ -48,10 +48,12 @@ similar to `$_basekernver`. The version of the software as released from the author (e.g., '2.7.1'). The variable is not allowed to contain colons or hyphens. + -The `pkgver` variable can be automatically updated by providing a `pkgver()` function -in the PKGBUILD that outputs the new package version. This is run after downloading -and extracting the sources so can use those files in determining the new `pkgver`. -This is most useful when used with sources from version control systems (see below). +The `pkgver` variable can be automatically updated by providing a `pkgver()` +function in the PKGBUILD that outputs the new package version. +This is run after downloading and extracting the sources so it can use those +files in determining the new `pkgver`. +This is most useful when used with sources from version control systems (see +below). *pkgrel*:: This is the release number specific to the Arch Linux release. This @@ -62,7 +64,8 @@ This is most useful when used with sources from version control systems (see bel *pkgdesc*:: This should be a brief description of the package and its functionality. - Try to keep the description to one line of text and not use the package's name. + Try to keep the description to one line of text and to not use the package's + name. *epoch*:: Used to force the package to be seen as newer than any previous versions @@ -75,7 +78,7 @@ This is most useful when used with sources from version control systems (see bel *url*:: This field contains a URL that is associated with the software being - packaged. Typically the project's website. + packaged. This is typically the project's web site. *license (array)*:: This field specifies the license(s) that apply to the package. @@ -91,13 +94,13 @@ This is most useful when used with sources from version control systems (see bel *install*:: Specifies a special install script that is to be included in the package. - This file should reside in the same directory as the PKGBUILD, and will + This file should reside in the same directory as the PKGBUILD and will be copied into the package by makepkg. It does not need to be included in the source array (e.g., `install=$pkgname.install`). *changelog*:: Specifies a changelog file that is to be included in the package. - This file should reside in the same directory as the PKGBUILD, and will + This file should reside in the same directory as the PKGBUILD and will be copied into the package by makepkg. It does not need to be included in the source array (e.g., `changelog=$pkgname.changelog`). @@ -105,10 +108,10 @@ This is most useful when used with sources from version control systems (see bel An array of source files required to build the package. Source files must either reside in the same directory as the PKGBUILD, or be a fully-qualified URL that makepkg can use to download the file. - To make the PKGBUILD as useful as possible, use the `$pkgname` and `$pkgver` - variables if possible when specifying the download location. Compressed files - will be extracted automatically unless found in - the noextract array described below. + To simplify the maintenance of PKGBUILDs, use the `$pkgname` and `$pkgver` + variables when specifying the download location, if possible. + Compressed files will be extracted automatically unless found in the + noextract array described below. + It is also possible to change the name of the downloaded file, which is helpful with weird URLs and for handling multiple source files with the same @@ -118,12 +121,12 @@ makepkg also supports building developmental versions of packages using sources downloaded from version control systems (VCS). For more information, see <<VCS,Using VCS Sources>> below. + -Files in the source array with extensions `.sig`, `.sign` or `.asc` are recognized by -makepkg as PGP signatures and will be automatically used to verify the integrity -of the corresponding source file. +Files in the source array with extensions `.sig`, `.sign` or, `.asc` are +recognized by makepkg as PGP signatures and will be automatically used to verify +the integrity of the corresponding source file. *noextract (array)*:: - An array of filenames corresponding to those from the source array. Files + An array of file names corresponding to those from the source array. Files listed here will not be extracted with the rest of the source files. This is useful for packages that use compressed data directly. @@ -152,10 +155,10 @@ of the corresponding source file. files should use `arch=('any')`. *backup (array)*:: - An array of filenames, without preceding slashes, that + An array of file names, without preceding slashes, that should be backed up if the package is removed or upgraded. This is - commonly used for packages placing configuration files in /etc. See - Handling Config Files in linkman:pacman[8] for more information. + commonly used for packages placing configuration files in '/etc'. See + `"Handling Config Files"` in linkman:pacman[8] for more information. *depends (array)*:: An array of packages this package depends on to run. Entries in @@ -168,7 +171,7 @@ of the corresponding source file. If the dependency name appears to be a library (ends with .so), makepkg will try to find a binary that depends on the library in the built package and append the version needed by the binary. Appending the version yourself -disables auto detection. +disables automatic detection. *makedepends (array)*:: An array of packages this package depends on to build but are not @@ -209,7 +212,7 @@ only specific versions of a package may be provided. + If the provision name appears to be a library (ends with .so), makepkg will try to find the library in the built package and append the correct -version. Appending the version yourself disables auto detection. +version. Appending the version yourself disables automatic detection. *replaces (array)*:: An array of packages this package should replace. This can be used @@ -289,13 +292,13 @@ Packaging Functions ------------------- In addition to the above directives, PKGBUILDs require a set of functions that -provide instructions to build and install the package. As a minimum, the PKGBUILD -must contain a package() function which installs all the package's files into the -packaging directory, with optional prepare(), build() and check() being used to -create those files from source. +provide instructions to build and install the package. As a minimum, the +PKGBUILD must contain a `package()` function which installs all the package's +files into the packaging directory, with optional `prepare()`, `build()`, and +`check()` functions being used to create those files from source. *package() Function*:: - The package() function is used to install files into the directory that + The `package()` function is used to install files into the directory that will become the root directory of the built package and is run after all the optional functions listed below. When specified in combination with the fakeroot BUILDENV option in linkman:makepkg.conf[5], fakeroot usage @@ -303,41 +306,41 @@ create those files from source. be run as the user calling makepkg. *prepare() Function*:: - An optional prepare() function can be specified in which operations that - are to be run in order to prepare the sources for building (such as - patching) are performed. This function is run after the source extraction - and before the build() function and is skipped when source extraction is - skipped. + An optional `prepare()` function can be specified in which operations to + prepare the sources for building, such as patching, are performed. This + function is run after the source extraction and before the `build()` + function. The `prepare()` function is skipped when source extraction + is skipped. *build() Function*:: - The optional build() function is use to compile and/or adjust the source - files in preparation to be installed by the package() function. This is - directly sourced and executed by makepkg, so anything that bash or the + The optional `build()` function is use to compile and/or adjust the source + files in preparation to be installed by the `package()` function. This is + directly sourced and executed by makepkg, so anything that Bash or the system has available is available for use here. Be sure any exotic - commands used are covered by `makedepends`. + commands used are covered by the `makedepends` array. + -If you create any variables of your own in the build function, it is -recommended to use the bash `local` keyword to scope the variable to inside -the build function. +If you create any variables of your own in the `build()` function, it is +recommended to use the Bash `local` keyword to scope the variable to inside +the `build()` function. *check() Function*:: - An optional check() function can be specified in which a package's - test-suite may be run. This function is run between the build() and - package() functions. Be sure any exotic commands used are covered by - `checkdepends`. + An optional `check()` function can be specified in which a package's + test-suite may be run. This function is run between the `build()` and + `package()` functions. Be sure any exotic commands used are covered by the + `checkdepends` array. -All of the above variables such as `$pkgname` and `$pkgver` are available for use -in the build function. In addition, makepkg defines the following variables for use -during the build and install process: +All of the above variables such as `$pkgname` and `$pkgver` are available for +use in the `build()` function. In addition, makepkg defines the following +variables for use during the build and install process: *srcdir*:: - This contains the directory where makepkg extracts, or copies, all source - files. + This contains the directory where makepkg extracts, or copies, all source + files. *pkgdir*:: - This contains the directory where makepkg bundles the installed package - (this directory will become the root directory of your built package). - This variable should only be used in the package() function. + This contains the directory where makepkg bundles the installed package. + This directory will become the root directory of your built package. This + variable should only be used in the `package()` function. *startdir*:: This contains the absolute path to the directory where the PKGBUILD is @@ -362,8 +365,8 @@ An optional global directive is available when building a split package: *pkgbase*:: The name used to refer to the group of packages in the output of makepkg - and in the naming of source-only tarballs. If not specified, the first - element in the `pkgname` array is used. The variable is not allowed to + and in the naming of source-only tarballs. If not specified, the first + element in the `pkgname` array is used. The variable is not allowed to begin with a hyphen. Install/Upgrade/Remove Scripting @@ -377,7 +380,7 @@ self-explanatory. Note that during an upgrade operation, none of the install or remove scripts will be called. Scripts are passed either one or two ``full version strings'', where a full -version string is either 'pkgver-pkgrel' or 'epoch:pkgver-pkgrel' if epoch is +version string is either 'pkgver-pkgrel' or 'epoch:pkgver-pkgrel', if epoch is non-zero. *pre_install*:: @@ -415,10 +418,12 @@ reference with all of the available functions defined. Using VCS Sources[[VCS]] ------------------------ -Building a developmental version of a package using sources from a version control -system (VCS) is enabled by specifying the source in the form -`source=('folder::url#fragment')`. Currently makepkg supports the `bzr`, `git`, `hg` and -`svn` protocols. +Building a developmental version of a package using sources from a version +control system (VCS) is enabled by specifying the source in the form +`source=('folder::url#fragment')`. Currently makepkg supports the Bazaar, Git, +Subversion, and Mercurial version control systems. For other version control +systems, manual cloning of upstream repositories must be done in the `prepare()` +function. The source URL is divided into three components: @@ -427,11 +432,12 @@ The source URL is divided into three components: source into. *url*:: - The url to the VCS repo. This must include the the vcs in the URL protocol for - makepkg to recognize this as a VCS source. If the protocol does not include - the VCS name, it can be added by prefixing the URL with `vcs+`. For example, - using a git repository over `http` would have a source URL in the form - `git+http://...`. + The URL to the VCS repository. This must include the VCS in the URL protocol + for makepkg to recognize this as a VCS source. If the protocol does not + include the VCS name, it can be added by prefixing the URL with `vcs+`. For + example, using a Git repository over HTTPS would have a source URL in the + form: + `git+https://...`. *fragment*:: (optional) Allows specifying a revision number or branch for makepkg to checkout @@ -455,7 +461,7 @@ Example ------- The following is an example PKGBUILD for the 'patch' package. For more examples, look through the build files of your distribution's packages. For -those using Arch Linux, consult the ABS tree. +those using Arch Linux, consult the Arch Build System (ABS) tree. [source,sh] ------------------------------- diff --git a/doc/footer.txt b/doc/footer.txt index ccb931ce..af19304e 100644 --- a/doc/footer.txt +++ b/doc/footer.txt @@ -8,7 +8,7 @@ information on pacman and its related tools. Bugs ---- -Bugs? You must be kidding, there are no bugs in this software. But if we +Bugs? You must be kidding; there are no bugs in this software. But if we happen to be wrong, send us an email with as much detail as possible to mailto:pacman-dev@archlinux.org[]. diff --git a/doc/makepkg-template.1.txt b/doc/makepkg-template.1.txt new file mode 100644 index 00000000..8fa5c2e1 --- /dev/null +++ b/doc/makepkg-template.1.txt @@ -0,0 +1,120 @@ +///// +vim:set ts=4 sw=4 syntax=asciidoc noet spell spelllang=en_us: +///// +makepkg-template(1) +=================== + +Name +---- +makepkg-template - package build templating utility + + +Synopsis +-------- +'makepkg-template' [options] + + +Description +----------- + +'makepkg-template' is a script to ease the work of maintaining multiple similar +PKGBUILDs. It allows you to move most of the code from the PKGBUILD into a +template file and uses markers to allow in-place updating of existing PKGBUILDs +if the template has been changed. + +Template files can contain any code allowed in a PKGBUILD. You can think of +them like external files included with "." or "source", but they will be +inlined into the PKGBUILD by 'makepkg-template' so you do not depend on the +template file when building the package. + +Markers are bash comments in the form of: + + # template start; key=value; key2=value2; ... + +and + + # template end; + +Currently used keys are: name (mandatory) and version. Template names are limited to +alphanumerics, "@", "+", ".", "-" and "_". Versions are limited to numbers and ".". + +For initial creation there is a one line short cut which does not need an end marker: + + # template input; key=value; + +Using this short-cut will result in 'makepkg-template' replacing it with start +and end markers and the template code on the first run. + +Template files should be stored in one directory and filenames should be +"$template_name-$version.template" with a symlink "$template_name.template" +pointing to the most recent template. If the version is not set in the marker, +'makepkg-template' will automatically use the most recent version of the +template, otherwise the specified version will be used. This allows for easier +verification of untrusted PKGBUILDs if the template is trusted. You verify the +non-template code and then use a command similar to this: + + diff -u <(makepkg-template -o -) PKGBUILD + +Template files may also contain markers leading to nested templates in the +resulting PKGBUILD. If you use markers in a template, please set the version +you used/tested with in the start/input marker so other people can properly +recreate from templates. + +Options +------- + +*-p, \--input* <build script>:: + Read the package script `build script` instead of the default. + +*-o, \--output* <build script>:: + Write the updated file to `build script` instead of overwriting the input file. + +*-n, \--newest*:: + Always use the newest available template file. + +*\--template-dir* <dir>:: + Change the dir where we are looking for template files. + +Example PKGBUILD +---------------- + + pkgname=perl-config-simple + pkgver=4.58 + pkgrel=1 + pkgdesc="simple configuration file class" + arch=('any') + license=('PerlArtistic' 'GPL') + depends=('perl') + source=("http://search.cpan.org/CPAN/authors/id/S/SH/SHERZODR/Config-Simple-${pkgver}.tar.gz") + md5sums=('f014aec54f0a1e2e880d317180fce502') + _distname="Config-Simple" + + # template start; name=perl-module; version=1.0; + _distdir="${_distname}-${pkgver}" + url="https://metacpan.org/release/${_distname}" + options+=('!emptydirs') + + build() { + cd "$srcdir/$_distdir" + perl Makefile.PL INSTALLDIRS=vendor + make + } + + check() { + cd "$srcdir/$_distdir" + make test + } + + package() { + cd "$srcdir/$_distdir" + make DESTDIR="$pkgdir" install + } + # template end; + + + +See Also +-------- +linkman:makepkg[8], linkman:PKGBUILD[5] + +include::footer.txt[] diff --git a/doc/makepkg.8.txt b/doc/makepkg.8.txt index 53a78677..899858e4 100644 --- a/doc/makepkg.8.txt +++ b/doc/makepkg.8.txt @@ -165,6 +165,9 @@ Options *\--nocheck*:: Do not run the check() function in the PKGBUILD or handle the checkdepends. +*\--noprepare*:: + Do not run the prepare() function in the PKGBUILD. + *\--sign*:: Sign the resulting package with gpg, overriding the setting in linkman:makepkg.conf[5]. @@ -226,6 +229,10 @@ Environment Variables Folder where the package will be built. Overrides the corresponding value defined in linkman:makepkg.conf[5]. +**CARCH=**"(i686|x86_64)":: + Force build for a specific architecture. Useful for cross-compiling. + Overrides the corresponding value defined in linkman:makepkg.conf[5]. + Configuration ------------- See linkman:makepkg.conf[5] for more details on configuring makepkg using the diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 189e1137..1cc1eaa4 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -17,17 +17,17 @@ Description ----------- Pacman is a package management utility that tracks installed packages on a Linux system. It features dependency support, package groups, install and uninstall -hooks, and the ability to sync your local machine with a remote ftp server to +hooks, and the ability to sync your local machine with a remote repository to automatically upgrade packages. Pacman packages are a zipped tar format. -Since version 3.0.0, pacman has been the frontend to linkman:libalpm[3], the +Since version 3.0.0, pacman has been the front-end to linkman:libalpm[3], the ``Arch Linux Package Management'' library. This library allows alternative -front ends to be written (for instance, a GUI front end). +front-ends to be written (for instance, a GUI front-end). Invoking pacman involves specifying an operation with any potential options and -targets to operate on. A 'target' is usually a package name, filename, URL, or +targets to operate on. A 'target' is usually a package name, file name, URL, or a search string. Targets can be provided as command line arguments. -Additionally, if stdin is not from a terminal and a single dash (-) is passed +Additionally, if stdin is not from a terminal and a single hyphen (-) is passed as an argument, targets will be read from stdin. @@ -44,7 +44,7 @@ Operations packages and their files, as well as meta-information about individual packages (dependencies, conflicts, install date, build date, size). This can be run against the local package database or can be used on - individual '.tar.gz' packages. In the first case, if no package names + individual package files. In the first case, if no package names are provided in the command line, all installed packages will be queried. Additionally, various filters can be applied on the package list. See <<QO,Query Options>> below. @@ -58,19 +58,19 @@ Operations See <<RO,Remove Options>> below. *-S, \--sync*:: - Synchronize packages. Packages are installed directly from the ftp - servers, including all dependencies required to run the packages. For + Synchronize packages. Packages are installed directly from the remote + repositories, including all dependencies required to run the packages. For example, `pacman -S qt` will download and install qt and all the - packages it depends on. If a package name exists in more than one repo, the - repo can be explicitly specified to clarify the package to install: - `pacman -S testing/qt`. You can also specify version requirements: - `pacman -S "bash>=3.2"`. (Quotes are needed, otherwise your shell - interprets ">" as redirection to file.) + packages it depends on. If a package name exists in more than one + repository, the repository can be explicitly specified to clarify the + package to install: `pacman -S testing/qt`. You can also specify version + requirements: `pacman -S "bash>=3.2"`. Quotes are needed, otherwise the + shell interprets ">" as redirection to a file. + In addition to packages, groups can be specified as well. For example, if gnome is a defined package group, then `pacman -S gnome` will provide a prompt allowing you to select which packages to install from a numbered list. -The package selection is specified using a space and/or comma separated list of +The package selection is specified using a space- and/or comma-separated list of package numbers. Sequential packages may be selected by specifying the first and last package numbers separated by a hyphen (`-`). Excluding packages is achieved by prefixing a number or range of numbers with a caret (`^`). @@ -81,7 +81,7 @@ provide the same functionality as foo will be searched for. If any package is found, it will be installed. A selection prompt is provided if multiple packages providing foo are found. + -You can also use `pacman -Su` to upgrade all packages that are out of date. See +You can also use `pacman -Su` to upgrade all packages that are out-of-date. See <<SO,Sync Options>> below. When upgrading, pacman performs version comparison to determine which packages need upgrading. This behavior operates as follows: @@ -91,7 +91,7 @@ to determine which packages need upgrading. This behavior operates as follows: 1 < 1.0 < 1.1 < 1.1.1 < 1.2 < 2.0 < 3.0.0 + Additionally, version strings can have an 'epoch' value defined that will -overrule any version comparison (unless the epoch values are equal). This is +overrule any version comparison, unless the epoch values are equal. This is specified in an `epoch:version-rel` format. For example, `2:1.0-1` is always greater than `1:3.6-1`. @@ -104,16 +104,16 @@ greater than `1:3.6-1`. *-U, \--upgrade*:: Upgrade or add package(s) to the system and install the required - dependencies from sync repos. Either a URL or file path can be + dependencies from sync repositories. Either a URL or file path can be specified. This is a ``remove-then-add'' process. See <<UO,Upgrade Options>> below; also see <<HCF,Handling Config Files>> for an explanation - on how pacman takes care of config files. + on how pacman takes care of configuration files. *-V, \--version*:: Display version and exit. *-h, \--help*:: - Display syntax for the given operation. If no operation was supplied + Display syntax for the given operation. If no operation was supplied, then the general syntax is shown. @@ -121,16 +121,17 @@ Options ------- *-b, \--dbpath* <path>:: Specify an alternative database location (a typical default is - +{localstatedir}/lib/pacman+). This should not be used unless you know what you are - doing. *NOTE*: if specified, this is an absolute path and the root path is + +{localstatedir}/lib/pacman+). This should not be used unless you know what + you are doing. + *NOTE*: if specified, this is an absolute path, and the root path is not automatically prepended. *-r, \--root* <path>:: Specify an alternative installation root (default is `/`). This should not be used as a way to install software into `/usr/local` instead of `/usr`. This option is used if you want to install a package on a - temporary mounted partition that is "owned" by another system. - *NOTE*: if database path or logfile are not specified on either the + temporarily mounted partition that is "owned" by another system. + *NOTE*: If database path or log file are not specified on either the command line or in linkman:pacman.conf[5], their default location will be inside this root path. @@ -142,14 +143,15 @@ Options *\--cachedir* <dir>:: Specify an alternative package cache location (a typical default is - +{localstatedir}/cache/pacman/pkg+). Multiple cache directories can be specified, - and they are tried in the order they are passed to pacman. *NOTE*: this - is an absolute path, the root path is not automatically prepended. + +{localstatedir}/cache/pacman/pkg+). Multiple cache directories can be + specified, and they are tried in the order they are passed to pacman. + *NOTE*: This is an absolute path, and the root path is not automatically + prepended. *\--color* <when>:: - Specify when to enable coloring, can be 'always', 'never' or 'auto'. Always - forces colours on, never forces colours off, and auto only automatically enables - colours when outputting onto a tty. + Specify when to enable coloring. Valid options are 'always', 'never', or + 'auto'. 'always' forces colors on; 'never' forces colors off; and 'auto' only + automatically enables colors when outputting onto a tty. *\--config* <file>:: Specify an alternate configuration file. @@ -163,8 +165,8 @@ Options typical default is +{sysconfdir}/pacman.d/gnupg+). This directory should contain two files: `pubring.gpg` and `trustdb.gpg`. `pubring.gpg` holds the public keys of all packagers. `trustdb.gpg` contains a so-called trust database, which - specifies that the keys are authentic and trusted. *NOTE*: this is an absolute - path, the root path is not automatically prepended. + specifies that the keys are authentic and trusted. *NOTE*: This is an absolute + path, and the root path is not automatically prepended. *\--logfile* <file>:: Specify an alternate log file. This is an absolute path, regardless of @@ -183,7 +185,7 @@ Transaction Options (apply to '-S', '-R' and '-U') system. Specify this option twice to skip all dependency checks. *\--dbonly*:: - Adds/Removes the database entry only, leaves all files in place. + Adds/removes the database entry only, leaving all files in place. *\--noprogressbar*:: Do not show a progress bar when downloading files. This can be useful @@ -197,12 +199,12 @@ Transaction Options (apply to '-S', '-R' and '-U') Only print the targets instead of performing the actual operation (sync, remove or upgrade). Use '\--print-format' to specify how targets are displayed. The default format string is "%l", which displays URLs with - '-S', filenames with '-U' and pkgname-pkgver with '-R'. + '-S', file names with '-U', and pkgname-pkgver with '-R'. *\--print-format* <format>:: Specify a printf-like format to control the output of the '\--print' operation. The possible attributes are: %n for pkgname, %v for pkgver, - %l for location, %r for repo and %s for size. + %l for location, %r for repo, and %s for size. Upgrade Options (apply to '-S' and '-U')[[UO]] -------------------------------------------- @@ -217,7 +219,7 @@ Upgrade Options (apply to '-S' and '-U')[[UO]] *\--asdeps*:: Install packages non-explicitly; in other words, fake their install reason to be installed as a dependency. This is useful for makepkg and other - build from source tools that need to install dependencies before building + build-from-source tools that need to install dependencies before building the package. *\--asexplicit*:: @@ -232,12 +234,12 @@ Upgrade Options (apply to '-S' and '-U')[[UO]] with a comma. *\--ignoregroup* <group>:: - Directs pacman to ignore upgrades of all packages in 'group' even if + Directs pacman to ignore upgrades of all packages in 'group', even if there is one available. Multiple groups can be specified by separating them with a comma. *\--needed*:: - Do not reinstall the targets that are already up to date. + Do not reinstall the targets that are already up-to-date. Query Options[[QO]] @@ -269,8 +271,8 @@ Query Options[[QO]] *-k \--check*:: Check that all files owned by the given package(s) are present on the system. If packages are not specified or filter flags are not provided, - check all installed packages. Specifying this option twice will perform - more detailed file checking (including permissions, file sizes and + check all installed packages. Specifying this option twice will perform + more detailed file checking (including permissions, file sizes, and modification times) for packages that contain the needed mtree file. *-l, \--list*:: @@ -279,16 +281,16 @@ Query Options[[QO]] *-m, \--foreign*:: Restrict or filter output to packages that were not found in the sync - database(s). Typically these are packages that were downloaded manually + database(s). Typically these are packages that were downloaded manually and installed with '\--upgrade'. *-n, \--native*:: Restrict or filter output to packages that are found in the sync - database(s). This is the inverse filter of '\--foreign'. + database(s). This is the inverse filter of '\--foreign'. *-o, \--owns* <file>:: Search for packages that own the specified file(s). The path can be - relative or absolute and one or more files can be specified. + relative or absolute, and one or more files can be specified. *-p, \--file*:: Signifies that the package supplied on the command line is a file and @@ -296,8 +298,8 @@ Query Options[[QO]] This is useful in combination with '\--info' and '\--list'. *-q, \--quiet*:: - Show less information for certain query operations. (This is useful when - pacman's output is processed in a script.) Search will only show package + Show less information for certain query operations. This is useful when + pacman's output is processed in a script. Search will only show package names and not version, group, and description information; owns will only show package names instead of "file is owned by pkg" messages; group will only show package names and omit group names; list will only show @@ -315,9 +317,9 @@ Query Options[[QO]] installed package. *-u, \--upgrades*:: - Restrict or filter output to packages that are out of date on the local - system. (Only package versions are used to find outdated packages, - replacements are not checked here.) This option works best if the sync + Restrict or filter output to packages that are out-of-date on the local + system. Only package versions are used to find outdated packages; + replacements are not checked here. This option works best if the sync database is refreshed using '-Sy'. @@ -325,19 +327,19 @@ Remove Options[[RO]] -------------------- *-c, \--cascade*:: Remove all target packages, as well as all packages that depend on one - or more target packages. This operation is recursive, and must be used - with care since it can remove many potentially needed packages. + or more target packages. This operation is recursive and must be used + with care, since it can remove many potentially needed packages. *-n, \--nosave*:: Instructs pacman to ignore file backup designations. Normally, when a - file is removed from the system the database is checked to see if the + file is removed from the system, the database is checked to see if the file should be renamed with a '.pacsave' extension. *-s, \--recursive*:: Remove each target specified including all of their dependencies, provided that (A) they are not required by other packages; and (B) they were not explicitly installed by the user. This operation is recursive and analogous - to a backwards '\--sync' operation, and helps keep a clean system without + to a backwards '\--sync' operation, and it helps keep a clean system without orphans. If you want to omit condition (B), pass this option twice. *-u, \--unneeded*:: @@ -352,7 +354,7 @@ Sync Options[[SO]] Remove packages that are no longer installed from the cache as well as currently unused sync databases to free up disk space. When pacman downloads packages, it saves them in a cache directory. In addition, - databases are saved for every sync DB you download from, and are not + databases are saved for every sync DB you download from and are not deleted even if they are removed from the configuration file linkman:pacman.conf[5]. Use one '\--clean' switch to only remove packages that are no longer installed; use two to remove all files @@ -377,9 +379,9 @@ linkman:pacman.conf[5]. can be specified on the command line. *-q, \--quiet*:: - Show less information for certain sync operations. (This is useful when - pacman's output is processed in a script.) Search will only show package - names and not repo, version, group, and description information; list + Show less information for certain sync operations. This is useful when + pacman's output is processed in a script. Search will only show package + names and not repository, version, group, and description information; list will only show package names and omit databases and versions; group will only show package names and omit group names. @@ -390,16 +392,16 @@ linkman:pacman.conf[5]. be returned. *-u, \--sysupgrade*:: - Upgrades all packages that are out of date. Each currently-installed + Upgrades all packages that are out-of-date. Each currently-installed package will be examined and upgraded if a newer package exists. A - report of all packages to upgrade will be presented and the operation + report of all packages to upgrade will be presented, and the operation will not proceed without user confirmation. Dependencies are automatically resolved at this level and will be installed/upgraded if necessary. + -Pass this option twice to enable package downgrade; in this case pacman will -select sync packages whose version does not match with the local version. This -can be useful when the user switches from a testing repo to a stable one. +Pass this option twice to enable package downgrades; in this case, pacman will +select sync packages whose versions do not match with the local versions. This +can be useful when the user switches from a testing repository to a stable one. + Additional targets can also be specified manually, so that '-Su foo' will do a system upgrade and install/upgrade the foo package in the same operation. @@ -411,17 +413,17 @@ system upgrade and install/upgrade the foo package in the same operation. Download a fresh copy of the master package list from the server(s) defined in linkman:pacman.conf[5]. This should typically be used each time you use '\--sysupgrade' or '-u'. Passing two '\--refresh' or '-y' flags - will force a refresh of all package lists even if they appear to be up - to date. + will force a refresh of all package lists, even if they appear to be up- + to-date. Handling Config Files[[HCF]] ---------------------------- -Pacman uses the same logic as rpm to determine action against files that are -designated to be backed up. During an upgrade, 3 md5 hashes are used for each -backup file to determine the required action: one for the original file -installed, one for the new file that's about to be installed, and one for the -actual file existing on the filesystem. After comparing these 3 hashes, the +Pacman uses the same logic as 'rpm' to determine action against files that are +designated to be backed up. During an upgrade, three MD5 hashes are used for +each backup file to determine the required action: one for the original file +installed, one for the new file that is about to be installed, and one for the +actual file existing on the file system. After comparing these three hashes, the follow scenarios can result: original=X, current=X, new=X:: @@ -429,13 +431,13 @@ original=X, current=X, new=X:: new file. original=X, current=X, new=Y:: - The current file is the same as the original but the new one differs. + The current file is the same as the original, but the new one differs. Since the user did not ever modify the file, and the new one may contain - improvements or bugfixes, install the new file. + improvements or bug fixes, install the new file. original=X, current=Y, new=X:: Both package versions contain the exact same file, but the one on the - filesystem has been modified. Leave the current file in place. + file system has been modified. Leave the current file in place. original=X, current=Y, new=Y:: The new file is identical to the current file. Install the new file. @@ -445,6 +447,11 @@ original=X, current=Y, new=Z:: extension and warn the user. The user must then manually merge any necessary changes into the original file. +original=NULL, current=Y, new=Z:: + The package was not previously installed, and the file already exists on the + file system. Save the current file with a '.pacorig' extension, install the + new file, and warn the user. + Examples -------- diff --git a/doc/repo-add.8.txt b/doc/repo-add.8.txt index 049195a7..80f58658 100644 --- a/doc/repo-add.8.txt +++ b/doc/repo-add.8.txt @@ -75,6 +75,10 @@ repo-add Options Only add packages that are not already in the database. Warnings will be printed upon detection of existing packages, but they will not be re-added. +*-R, \--remove*:: + Remove old package files from the disk when updating their entry in the + database. + See Also -------- linkman:makepkg[8], linkman:pacman[8], linkman:pkgdelta[8] diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 3ef81e37..c20e7c61 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -197,30 +197,25 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: * (F=file, N=node, S=symlink, D=dir) - * | F/N | S | D - * non-existent | 1 | 2 | 3 - * F/N | 4 | 5 | 6 - * S | 7 | 8 | 9 - * D | 10 | 11 | 12 + * | F/N | D + * non-existent | 1 | 2 + * F/N | 3 | 4 + * D | 5 | 6 * - * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here. - * 4,5,6,7,8- conflict checks should have caught this. either overwrite + * 1,2- extract, no magic necessary. lstat (_alpm_lstat) will fail here. + * 3,4- conflict checks should have caught this. either overwrite * or backup the file. - * 9- follow the symlink, hopefully it is a directory, check it. - * 10- file replacing directory- don't allow it. - * 11- don't extract symlink- a dir exists here. we don't want links to - * links, etc. - * 12- skip extraction, dir already exists. + * 5- file replacing directory- don't allow it. + * 6- skip extraction, dir already exists. */ - /* do both a lstat and a stat, so we can see what symlinks point to */ - struct stat lsbuf, sbuf; - if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) { - /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */ + struct stat lsbuf; + if(_alpm_lstat(filename, &lsbuf) != 0) { + /* cases 1,2: file doesn't exist, skip all backup checks */ } else { if(S_ISDIR(lsbuf.st_mode)) { if(S_ISDIR(entrymode)) { - /* case 12: existing dir, ignore it */ + /* case 6: existing dir, ignore it */ if(lsbuf.st_mode != entrymode) { /* if filesystem perms are different than pkg perms, warn user */ mode_t mask = 07777; @@ -237,33 +232,18 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, archive_read_data_skip(archive); return 0; } else { - /* case 10/11: trying to overwrite dir with file/symlink, don't allow it */ + /* case 5: trying to overwrite dir with file, don't allow it */ _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), filename); archive_read_data_skip(archive); return 1; } - } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) { - /* case 9: existing symlink, dir in package */ - if(S_ISDIR(sbuf.st_mode)) { - /* the symlink on FS is to a directory, so we'll use it */ - _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping symlink overwrite of %s\n", - filename); - archive_read_data_skip(archive); - return 0; - } else { - /* this is BAD. symlink was not to a directory */ - _alpm_log(handle, ALPM_LOG_ERROR, _("extract: symlink %s does not point to dir\n"), - filename); - archive_read_data_skip(archive); - return 1; - } - } else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) { - /* case 6: trying to overwrite file with dir */ + } else if(S_ISDIR(entrymode)) { + /* case 4: trying to overwrite file with dir */ _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", filename); - } else if(S_ISREG(entrymode)) { - /* case 4,7: */ + } else { + /* case 3: */ /* if file is in NoUpgrade, don't touch it */ if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) { notouch = 1; @@ -273,8 +253,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, /* check newpkg first, so that adding backup files is retroactive */ backup = _alpm_needbackup(entryname, newpkg); if(backup) { - /* if we force hash_orig to be non-NULL retroactive backup works */ - hash_orig = ""; needbackup = 1; } @@ -288,8 +266,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, } } } - /* else if(S_ISLNK(entrymode)) */ - /* case 5,8: don't need to do anything special */ } /* we need access to the original entryname later after calls to @@ -332,81 +308,80 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); - if(!oldpkg) { - if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) { - /* looks like we have a local file that has a different hash as the - * file in the package, move it to a .pacorig */ + if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { + /* local and new files are the same, no sense in installing the file + * over itself, regardless of what the original file was */ + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: leaving existing file in place\n"); + unlink(checkfile); + } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { + /* original and new files are the same, leave the local version alone, + * including any user changes */ + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: leaving existing file in place\n"); + unlink(checkfile); + } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) { + /* installed file has NOT been changed by user, + * update to the new version */ + _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", + entryname_orig); + if(try_rename(handle, checkfile, filename)) { + errors++; + } + } else { + /* none of the three files matched another, unpack the new file alongside + * the local file */ + + if(oldpkg) { + char *newpath; + size_t newlen = strlen(filename) + strlen(".pacnew") + 1; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: keeping current file and installing" + " new one with .pacnew ending\n"); + + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacnew", filename); + + if(try_rename(handle, checkfile, newpath)) { + errors++; + } else { + _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), + filename, newpath); + alpm_logaction(handle, ALPM_CALLER_PREFIX, + "warning: %s installed as %s\n", filename, newpath); + } + + free(newpath); + } else { char *newpath; - size_t newlen = strlen(filename) + 9; + size_t newlen = strlen(filename) + strlen(".pacorig") + 1; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: saving existing file with a .pacorig ending" + " and installing a new one\n"); + MALLOC(newpath, newlen, errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); snprintf(newpath, newlen, "%s.pacorig", filename); /* move the existing file to the "pacorig" */ if(try_rename(handle, filename, newpath)) { - errors++; - errors++; + errors++; /* failed rename filename -> filename.pacorig */ + errors++; /* failed rename checkfile -> filename */ } else { /* rename the file we extracted to the real name */ if(try_rename(handle, checkfile, filename)) { errors++; } else { - _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); + _alpm_log(handle, ALPM_LOG_WARNING, + _("%s saved as %s\n"), filename, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", filename, newpath); } } - free(newpath); - } else { - /* local file is identical to pkg one, so just remove pkg one */ - unlink(checkfile); - } - } else if(hash_orig) { - /* the fun part */ - - if(hash_local && strcmp(hash_orig, hash_local) == 0) { - /* installed file has NOT been changed by user */ - if(hash_pkg && strcmp(hash_orig, hash_pkg) != 0) { - _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", - entryname_orig); - if(try_rename(handle, checkfile, filename)) { - errors++; - } - } else { - /* no sense in installing the same file twice, install - * ONLY if the original and package hashes differ */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } - } else if(hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { - /* originally installed file and new file are the same - this - * implies the case above failed - i.e. the file was changed by a - * user */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } else if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { - /* this would be magical. The above two cases failed, but the - * user changes just so happened to make the new file exactly the - * same as the one in the package... skip it */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } else { - char *newpath; - size_t newlen = strlen(filename) + 8; - _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" - " new one with .pacnew ending\n"); - MALLOC(newpath, newlen, - errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); - snprintf(newpath, newlen, "%s.pacnew", filename); - if(try_rename(handle, checkfile, newpath)) { - errors++; - } else { - _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), - filename, newpath); - alpm_logaction(handle, ALPM_CALLER_PREFIX, - "warning: %s installed as %s\n", filename, newpath); - } free(newpath); } } diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index ccbdd1c6..c6d97c59 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -217,7 +217,6 @@ typedef struct _alpm_file_t { typedef struct _alpm_filelist_t { size_t count; alpm_file_t *files; - char **resolved_path; } alpm_filelist_t; /** Local package or package file backup entry */ @@ -405,10 +404,9 @@ typedef enum _alpm_question_t { ALPM_QUESTION_REPLACE_PKG = (1 << 1), ALPM_QUESTION_CONFLICT_PKG = (1 << 2), ALPM_QUESTION_CORRUPTED_PKG = (1 << 3), - ALPM_QUESTION_LOCAL_NEWER = (1 << 4), - ALPM_QUESTION_REMOVE_PKGS = (1 << 5), - ALPM_QUESTION_SELECT_PROVIDER = (1 << 6), - ALPM_QUESTION_IMPORT_KEY = (1 << 7) + ALPM_QUESTION_REMOVE_PKGS = (1 << 4), + ALPM_QUESTION_SELECT_PROVIDER = (1 << 5), + ALPM_QUESTION_IMPORT_KEY = (1 << 6) } alpm_question_t; /** Question callback */ @@ -1043,7 +1041,7 @@ int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason); * @param path the path to search for in the package * @return a pointer to the matching file or NULL if not found */ -char *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path); +alpm_file_t *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path); /* * Signatures @@ -1268,6 +1266,7 @@ typedef enum _alpm_errno_t { ALPM_ERR_PKG_INVALID, ALPM_ERR_PKG_INVALID_CHECKSUM, ALPM_ERR_PKG_INVALID_SIG, + ALPM_ERR_PKG_MISSING_SIG, ALPM_ERR_PKG_OPEN, ALPM_ERR_PKG_CANT_REMOVE, ALPM_ERR_PKG_INVALID_NAME, diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index bcd42b87..59f99f9b 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -21,6 +21,10 @@ #include <stdlib.h> #include <string.h> +/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include + * any other libalpm headers. + */ + /* libalpm */ #include "alpm_list.h" diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index 72c73785..3f3566b7 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -22,6 +22,10 @@ #include <stdlib.h> /* size_t */ +/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include + * any other libalpm headers. + */ + #ifdef __cplusplus extern "C" { #endif diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index cfe5fb36..5a709680 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -323,9 +323,13 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, } /* even if we don't have a sig, run the check code if level tells us to */ - if(has_sig || level & ALPM_SIG_PACKAGE) { + if(level & ALPM_SIG_PACKAGE) { const char *sig = syncpkg ? syncpkg->base64_sig : NULL; _alpm_log(handle, ALPM_LOG_DEBUG, "sig data: %s\n", sig ? sig : "<from .sig>"); + if(!has_sig && !(level & ALPM_SIG_PACKAGE_OPTIONAL)) { + handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG; + return -1; + } if(_alpm_check_pgp_helper(handle, pkgfile, sig, level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK, level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) { diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 18e29a89..a00efe5c 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -299,97 +299,73 @@ void _alpm_fileconflict_free(alpm_fileconflict_t *conflict) } /** - * @brief Recursively checks if a package owns all subdirectories and files in - * a directory. + * @brief Recursively checks if a set of packages own all subdirectories and + * files in a directory. * * @param handle the context handle * @param dirpath path of the directory to check - * @param pkg package being checked against + * @param pkgs packages being checked against * - * @return 1 if a package owns all subdirectories and files or a directory - * cannot be opened, 0 otherwise + * @return 1 if a package owns all subdirectories and files, 0 otherwise */ -static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, - alpm_pkg_t *pkg) +static int dir_belongsto_pkgs(alpm_handle_t *handle, const char *dirpath, + alpm_list_t *pkgs) { - alpm_list_t *i; - struct stat sbuf; - char path[PATH_MAX]; - char abspath[PATH_MAX]; + char path[PATH_MAX], full_path[PATH_MAX]; DIR *dir; struct dirent *ent = NULL; - const char *root = handle->root; - - /* check directory is actually in package - used for subdirectory checks */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(pkg)); - if(!alpm_filelist_contains(alpm_pkg_get_files(pkg), dirpath)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "directory %s not in package %s\n", dirpath, pkg->name); - return 0; - } - - /* TODO: this is an overly strict check but currently pacman will not - * overwrite a directory with a file (case 10/11 in add.c). Adjusting that - * is not simple as even if the directory is being unowned by a conflicting - * package, pacman does not sort this to ensure all required directory - * "removals" happen before installation of file/symlink */ - - /* check that no other _installed_ package owns the directory */ - for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { - if(pkg == i->data) { - continue; - } - _alpm_filelist_resolve(handle, alpm_pkg_get_files(i->data)); - if(alpm_filelist_contains(alpm_pkg_get_files(i->data), dirpath)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "file %s also in package %s\n", dirpath, - ((alpm_pkg_t*)i->data)->name); - return 0; - } - } - - /* check all files in directory are owned by the package */ - snprintf(abspath, PATH_MAX, "%s%s", root, dirpath); - dir = opendir(abspath); + snprintf(full_path, PATH_MAX, "%s%s", handle->root, dirpath); + dir = opendir(full_path); if(dir == NULL) { - return 1; + return 0; } while((ent = readdir(dir)) != NULL) { const char *name = ent->d_name; + int owned = 0; + alpm_list_t *i; + struct stat sbuf; if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; } + snprintf(path, PATH_MAX, "%s%s", dirpath, name); - snprintf(abspath, PATH_MAX, "%s%s", root, path); - if(stat(abspath, &sbuf) != 0) { - continue; - } - if(S_ISDIR(sbuf.st_mode)) { - if(dir_belongsto_pkg(handle, path, pkg)) { - continue; - } else { - closedir(dir); - return 0; - } - } else { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(pkg)); - if(alpm_filelist_contains(alpm_pkg_get_files(pkg), path)) { - continue; - } else { - closedir(dir); - _alpm_log(handle, ALPM_LOG_DEBUG, - "unowned file %s found in directory\n", path); - return 0; + snprintf(full_path, PATH_MAX, "%s%s", handle->root, path); + + for(i = pkgs; i && !owned; i = i->next) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) { + owned = 1; } } + + if(owned && stat(full_path, &sbuf) != 0 && S_ISDIR(sbuf.st_mode)) { + owned = dir_belongsto_pkgs(handle, path, pkgs); + } + + if(!owned) { + closedir(dir); + _alpm_log(handle, ALPM_LOG_DEBUG, + "unowned file %s found in directory\n", path); + return 0; + } } closedir(dir); return 1; } +static alpm_list_t *alpm_db_find_file_owners(alpm_db_t* db, const char *path) +{ + alpm_list_t *i, *owners = NULL; + for(i = alpm_db_get_pkgcache(db); i; i = i->next) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) { + owners = alpm_list_add(owners, i->data); + } + } + return owners; +} + /** * @brief Find file conflicts that may occur during the transaction. * @@ -417,11 +393,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, rootlen = strlen(handle->root); - /* make sure all files to be installed have been resolved */ - for(i = upgrade; i; i = i->next) { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(i->data)); - } - /* TODO this whole function needs a huge change, which hopefully will * be possible with real transactions. Right now we only do half as much * here as we do when we actually extract files in add.c with our 12 @@ -491,7 +462,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, * be freed. */ if(dbpkg) { /* older ver of package currently installed */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(dbpkg)); tmpfiles = _alpm_filelist_difference(alpm_pkg_get_files(p1), alpm_pkg_get_files(dbpkg)); } else { @@ -499,7 +469,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_filelist_t *fl = alpm_pkg_get_files(p1); size_t filenum; for(filenum = 0; filenum < fl->count; filenum++) { - tmpfiles = alpm_list_add(tmpfiles, fl->resolved_path[filenum]); + tmpfiles = alpm_list_add(tmpfiles, fl->files[filenum].name); } } @@ -514,6 +484,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, size_t pathlen; pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); + relative_path = path + rootlen; /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { @@ -522,30 +493,38 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, _alpm_log(handle, ALPM_LOG_DEBUG, "checking possible conflict: %s\n", path); - if(filestr[strlen(filestr) - 1] == '/') { - struct stat sbuf; + if(path[pathlen - 1] == '/') { if(S_ISDIR(lsbuf.st_mode)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file is a directory, not a conflict\n"); continue; } - stat(path, &sbuf); - if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(sbuf.st_mode)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "file is a symlink to a dir, hopefully not a conflict\n"); - continue; - } /* if we made it to here, we want all subsequent path comparisons to * not include the trailing slash. This allows things like file -> * directory replacements. */ path[pathlen - 1] = '\0'; - } - relative_path = path + rootlen; + /* Check if the directory was a file in dbpkg */ + if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_path)) { + size_t fslen = strlen(filestr); + _alpm_log(handle, ALPM_LOG_DEBUG, + "replacing package file with a directory, not a conflict\n"); + resolved_conflict = 1; + + /* go ahead and skip any files inside filestr as they will + * necessarily be resolved by replacing the file with a dir + * NOTE: afterward, j will point to the last file inside filestr */ + for( ; j->next; j = j->next) { + const char *filestr2 = j->next->data; + if(strncmp(filestr, filestr2, fslen) != 0) { + break; + } + } + } + } /* Check remove list (will we remove the conflicting local file?) */ for(k = rem; k && !resolved_conflict; k = k->next) { alpm_pkg_t *rempkg = k->data; - _alpm_filelist_resolve(handle, alpm_pkg_get_files(rempkg)); if(rempkg && alpm_filelist_contains(alpm_pkg_get_files(rempkg), relative_path)) { _alpm_log(handle, ALPM_LOG_DEBUG, @@ -556,20 +535,21 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, /* Look at all the targets to see if file has changed hands */ for(k = upgrade; k && !resolved_conflict; k = k->next) { - alpm_pkg_t *p2 = k->data; - if(!p2 || strcmp(p1->name, p2->name) == 0) { + alpm_pkg_t *localp2, *p2 = k->data; + if(!p2 || p1 == p2) { + /* skip p1; both p1 and p2 come directly from the upgrade list + * so they can be compared directly */ continue; } - alpm_pkg_t *localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); + localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); /* localp2->files will be removed (target conflicts are handled by CHECK 1) */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(localp2)); - if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), filestr)) { + if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), relative_path)) { /* skip removal of file, but not add. this will prevent a second * package from removing the file when it was already installed * by its new owner (whether the file is in backup array or not */ handle->trans->skip_remove = - alpm_list_add(handle->trans->skip_remove, strdup(filestr)); + alpm_list_add(handle->trans->skip_remove, strdup(relative_path)); _alpm_log(handle, ALPM_LOG_DEBUG, "file changed packages, adding to remove skiplist\n"); resolved_conflict = 1; @@ -577,41 +557,42 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, } /* check if all files of the dir belong to the installed pkg */ - if(!resolved_conflict && S_ISDIR(lsbuf.st_mode) && dbpkg) { - char *dir = malloc(strlen(filestr) + 2); - sprintf(dir, "%s/", filestr); - if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "checking if all files in %s belong to %s\n", - dir, dbpkg->name); - resolved_conflict = dir_belongsto_pkg(handle, dir, dbpkg); - } - free(dir); - } + if(!resolved_conflict && S_ISDIR(lsbuf.st_mode)) { + alpm_list_t *owners; + char *dir = malloc(strlen(relative_path) + 2); + sprintf(dir, "%s/", relative_path); + + owners = alpm_db_find_file_owners(handle->db_local, dir); + if(owners) { + alpm_list_t *pkgs = NULL, *diff; - /* check if a component of the filepath was a link. canonicalize the path - * and look for it in the old package. note that the actual file under - * consideration cannot itself be a link, as it might be unowned- path - * components can be safely checked as all directories are "unowned". */ - if(!resolved_conflict && dbpkg && !S_ISLNK(lsbuf.st_mode)) { - char rpath[PATH_MAX]; - if(realpath(path, rpath)) { - const char *relative_rpath = rpath + rootlen; - if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { + if(dbpkg) { + pkgs = alpm_list_add(pkgs, dbpkg); + } + pkgs = alpm_list_join(pkgs, alpm_list_copy(rem)); + if((diff = alpm_list_diff(owners, pkgs, _alpm_pkg_cmp))) { + /* dir is owned by files we aren't removing */ + /* TODO: with better commit ordering, we may be able to check + * against upgrades as well */ + alpm_list_free(diff); + } else { _alpm_log(handle, ALPM_LOG_DEBUG, - "package contained the resolved realpath\n"); - resolved_conflict = 1; + "checking if all files in %s belong to removed packages\n", + dir); + resolved_conflict = dir_belongsto_pkgs(handle, dir, owners); } + alpm_list_free(pkgs); + alpm_list_free(owners); } + free(dir); } /* is the file unowned and in the backup list of the new package? */ - if(!resolved_conflict && _alpm_needbackup(filestr, p1)) { + if(!resolved_conflict && _alpm_needbackup(relative_path, p1)) { alpm_list_t *local_pkgs = _alpm_db_get_pkgcache(handle->db_local); int found = 0; for(k = local_pkgs; k && !found; k = k->next) { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(k->data)); - if(alpm_filelist_contains(alpm_pkg_get_files(k->data), filestr)) { + if(alpm_filelist_contains(alpm_pkg_get_files(k->data), relative_path)) { found = 1; } } diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index a59f4fe1..86221807 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -111,6 +111,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err) return _("invalid or corrupted package (checksum)"); case ALPM_ERR_PKG_INVALID_SIG: return _("invalid or corrupted package (PGP signature)"); + case ALPM_ERR_PKG_MISSING_SIG: + return _("package missing required signature"); case ALPM_ERR_PKG_OPEN: return _("cannot open package file"); case ALPM_ERR_PKG_CANT_REMOVE: diff --git a/lib/libalpm/filelist.c b/lib/libalpm/filelist.c index 697dd23b..f8db9a33 100644 --- a/lib/libalpm/filelist.c +++ b/lib/libalpm/filelist.c @@ -25,199 +25,6 @@ #include "filelist.h" #include "util.h" -/** Helper function for comparing strings when sorting */ -static int _alpm_filelist_strcmp(const void *s1, const void *s2) -{ - return strcmp(*(char **)s1, *(char **)s2); -} - -/* TODO make sure callers check the return value so we can bail on errors. - * For now we soldier on as best we can, skipping paths that are too long to - * resolve and using the original filenames on memory errors. */ -/** - * @brief Resolves a symlink and its children. - * - * @attention Pre-condition: files must be sorted! - * - * @param files filelist to resolve - * @param i pointer to the index in files to start processing, will point to - * the last file processed on return - * @param path absolute path for the symlink being resolved - * @param root_len length of the root portion of path - * @param resolving is file \i in \files a symlink that needs to be resolved - * - * @return 0 on success, -1 on error - */ -int _alpm_filelist_resolve_link(alpm_filelist_t *files, size_t *i, - char *path, size_t root_len, int resolving) -{ - char *causal_dir = NULL; /* symlink being resolved */ - char *filename_r = NULL; /* resolved filename */ - size_t causal_dir_len = 0, causal_dir_r_len = 0; - - if(resolving) { - /* deal with the symlink being resolved */ - MALLOC(filename_r, PATH_MAX, goto error); - causal_dir = files->files[*i].name; - causal_dir_len = strlen(causal_dir); - if(realpath(path, filename_r) == NULL) { - files->resolved_path[*i] = causal_dir; - FREE(filename_r); - return -1; - } - causal_dir_r_len = strlen(filename_r + root_len) + 1; - if(causal_dir_r_len >= PATH_MAX) { - files->resolved_path[*i] = causal_dir; - FREE(filename_r); - return -1; - } - /* remove root_r from filename_r */ - memmove(filename_r, filename_r + root_len, causal_dir_r_len); - filename_r[causal_dir_r_len - 1] = '/'; - filename_r[causal_dir_r_len] = '\0'; - STRDUP(files->resolved_path[*i], filename_r, goto error); - (*i)++; - } - - for(; *i < files->count; (*i)++) { - char *filename = files->files[*i].name; - size_t filename_len = strlen(filename); - size_t filename_r_len = filename_len; - struct stat sbuf; - int exists; - - if(resolving) { - if(filename_len < causal_dir_len || strncmp(filename, causal_dir, causal_dir_len) != 0) { - /* not inside causal_dir anymore */ - break; - } - - filename_r_len = filename_len + causal_dir_r_len - causal_dir_len; - if(filename_r_len >= PATH_MAX) { - /* resolved path is too long */ - files->resolved_path[*i] = filename; - continue; - } - - strcpy(filename_r + causal_dir_r_len, filename + causal_dir_len); - } - - /* deal with files and paths too long to resolve*/ - if(filename[filename_len - 1] != '/' || root_len + filename_r_len >= PATH_MAX) { - if(resolving) { - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = filename; - } - continue; - } - - /* construct absolute path and stat() */ - strcpy(path + root_len, resolving ? filename_r : filename); - exists = !_alpm_lstat(path, &sbuf); - - /* deal with symlinks */ - if(exists && S_ISLNK(sbuf.st_mode)) { - _alpm_filelist_resolve_link(files, i, path, root_len, 1); - continue; - } - - /* deal with normal directories */ - if(resolving) { - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = filename; - } - - /* deal with children of non-existent directories to reduce lstat() calls */ - if(!exists) { - for((*i)++; *i < files->count; (*i)++) { - char *f = files->files[*i].name; - size_t f_len = strlen(f); - size_t f_r_len; - - if(f_len < filename_len || strncmp(f, filename, filename_len) != 0) { - /* not inside the non-existent dir anymore */ - break; - } - - f_r_len = f_len + causal_dir_r_len - causal_dir_len; - if(resolving && f_r_len <= PATH_MAX) { - strcpy(filename_r + causal_dir_r_len, f + causal_dir_len); - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = f; - } - } - (*i)--; - } - } - (*i)--; - - FREE(filename_r); - - return 0; - -error: - FREE(filename_r); - /* out of memory, set remaining files to their original names */ - for(; *i < files->count; (*i)++) { - files->resolved_path[*i] = files->files[*i].name; - } - (*i)--; - return -1; -} - -/** - * @brief Takes a file list and resolves all directory paths according to the - * filesystem - * - * @attention Pre-condition: files must be sorted! - * - * @note A symlink and directory at the same path in two difference packages - * causes a conflict so the filepath can not change as packages get installed - * - * @param handle the context handle - * @param files list of files to resolve - * - * @return 0 on success, -1 on error - */ -int _alpm_filelist_resolve(alpm_handle_t *handle, alpm_filelist_t *files) -{ - char path[PATH_MAX]; - size_t root_len, i = 0; - int ret = 0; - - if(!files || files->resolved_path) { - return 0; - } - - CALLOC(files->resolved_path, files->count, sizeof(char *), return -1); - - /* not much point in going on if we can't even resolve root */ - if(realpath(handle->root, path) == NULL){ - return -1; - } - root_len = strlen(path); - if(root_len + 1 >= PATH_MAX) { - return -1; - } - /* append '/' if root is not "/" */ - if(path[root_len - 1] != '/') { - path[root_len] = '/'; - root_len++; - path[root_len] = '\0'; - } - - ret = _alpm_filelist_resolve_link(files, &i, path, root_len, 0); - - qsort(files->resolved_path, files->count, sizeof(char *), - _alpm_filelist_strcmp); - - return ret; -} - - /* Returns the difference of the provided two lists of files. * Pre-condition: both lists are sorted! * When done, free the list but NOT the contained data. @@ -229,8 +36,8 @@ alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, size_t ctrA = 0, ctrB = 0; while(ctrA < filesA->count && ctrB < filesB->count) { - char *strA = filesA->resolved_path[ctrA]; - char *strB = filesB->resolved_path[ctrB]; + char *strA = filesA->files[ctrA].name; + char *strB = filesB->files[ctrB].name; int cmp = strcmp(strA, strB); if(cmp < 0) { @@ -247,7 +54,7 @@ alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, /* ensure we have completely emptied pA */ while(ctrA < filesA->count) { - ret = alpm_list_add(ret, filesA->resolved_path[ctrA]); + ret = alpm_list_add(ret, filesA->files[ctrA].name); ctrA++; } @@ -269,17 +76,17 @@ alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, char *strA, *strB; isdirA = 0; - strA = filesA->resolved_path[ctrA]; + strA = filesA->files[ctrA].name; if(strA[strlen(strA)-1] == '/') { isdirA = 1; - strA = strndup(filesA->resolved_path[ctrA], strlen(strA)-1); + strA = strndup(strA, strlen(strA)-1); } isdirB = 0; - strB = filesB->resolved_path[ctrB]; + strB = filesB->files[ctrB].name; if(strB[strlen(strB)-1] == '/') { isdirB = 1; - strB = strndup(filesB->resolved_path[ctrB], strlen(strB)-1); + strB = strndup(strB, strlen(strB)-1); } cmp = strcmp(strA, strB); @@ -297,7 +104,7 @@ alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, /* when not directories, item in both qualifies as an intersect */ if(! (isdirA && isdirB)) { - ret = alpm_list_add(ret, filesA->resolved_path[ctrA]); + ret = alpm_list_add(ret, filesA->files[ctrA].name); } ctrA++; ctrB++; @@ -323,11 +130,10 @@ int _alpm_files_cmp(const void *f1, const void *f2) return strcmp(file1->name, file2->name); } - -char SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, +alpm_file_t SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path) { - alpm_file_t key, *match; + alpm_file_t key; if(!filelist) { return NULL; @@ -335,17 +141,8 @@ char SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, key.name = (char *)path; - match = bsearch(&key, filelist->files, filelist->count, + return bsearch(&key, filelist->files, filelist->count, sizeof(alpm_file_t), _alpm_files_cmp); - - if(match) { - return match->name; - } else if(filelist->resolved_path) { - return bsearch(&path, filelist->resolved_path, filelist->count, - sizeof(char *), _alpm_filelist_strcmp); - } else { - return NULL; - } } /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/filelist.h b/lib/libalpm/filelist.h index bfab4165..66501f36 100644 --- a/lib/libalpm/filelist.h +++ b/lib/libalpm/filelist.h @@ -21,10 +21,6 @@ #include "alpm.h" -int _alpm_filelist_resolve_link(alpm_filelist_t *files, size_t *i, - char *path, size_t root_len, int resolving); -int _alpm_filelist_resolve(alpm_handle_t *handle, alpm_filelist_t *files); - alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, alpm_filelist_t *filesB); diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 098c8677..cfdbb3f8 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -606,9 +606,6 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) } } newpkg->files.count = pkg->files.count; - /* deliberately do not copy resolved_path as this is only used - * during conflict checking and the sorting of list does not readily - * allow keeping its efficient memory usage when copying */ } /* internal */ @@ -657,22 +654,9 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) free_deplist(pkg->replaces); FREELIST(pkg->groups); if(pkg->files.count) { - size_t i, j, k; - if(pkg->files.resolved_path) { - for(i = 0, j = 0; i < pkg->files.count; i++) { - for(k = j; k <= pkg->files.count; k++) { - if(pkg->files.resolved_path[i] == pkg->files.files[k].name) { - pkg->files.files[k].name = NULL; - j = k + 1; - break; - } - } - free(pkg->files.resolved_path[i]); - } - free(pkg->files.resolved_path); - } - for(j = 0; j < pkg->files.count; j++) { - FREE(pkg->files.files[j].name); + size_t i; + for(i = 0; i < pkg->files.count; i++) { + FREE(pkg->files.files[i].name); } free(pkg->files.files); } diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index d0cd613c..0b4f80cd 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -442,11 +442,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, return 1; } - /* we want to do a lstat here, and not a _alpm_lstat. - * if a directory in the package is actually a directory symlink on the - * filesystem, we want to work with the linked directory instead of the - * actual symlink */ - if(lstat(file, &buf)) { + if(_alpm_lstat(file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file); return 1; } @@ -462,7 +458,6 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, "keeping directory %s (could not count files)\n", file); } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), fileobj->name)) { - /* newpkg's filelist should have already been resolved by the caller */ _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (in new package)\n", file); } else if(dir_is_mountpoint(handle, file, &buf)) { @@ -484,9 +479,6 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, continue; } filelist = alpm_pkg_get_files(local_pkg); - /* This is too slow and only covers a rare case - Disable for now... */ - /* _alpm_filelist_resolve(handle, filelist); */ if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); @@ -584,7 +576,6 @@ static int remove_package_files(alpm_handle_t *handle, * so this removal operation doesn't kill them */ /* old package backup list */ newfiles = alpm_pkg_get_files(newpkg); - _alpm_filelist_resolve(handle, newfiles); for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) { const alpm_backup_t *backup = b->data; /* safety check (fix the upgrade026 pactest) */ diff --git a/proto/PKGBUILD-split.proto b/proto/PKGBUILD-split.proto index 672e7dfb..54e55579 100644 --- a/proto/PKGBUILD-split.proto +++ b/proto/PKGBUILD-split.proto @@ -24,8 +24,8 @@ backup=() options=() install= changelog= -source=($pkgbase-$pkgver.tar.gz - $pkgname-$pkgver.patch) +source=("$pkgbase-$pkgver.tar.gz" + "$pkgname-$pkgver.patch") noextract=() md5sums=() #generate with 'makepkg -g' diff --git a/proto/PKGBUILD.proto b/proto/PKGBUILD.proto index d4c01b80..5b854ceb 100644 --- a/proto/PKGBUILD.proto +++ b/proto/PKGBUILD.proto @@ -24,8 +24,8 @@ backup=() options=() install= changelog= -source=($pkgname-$pkgver.tar.gz - $pkgname-$pkgver.patch) +source=("$pkgname-$pkgver.tar.gz" + "$pkgname-$pkgver.patch") noextract=() md5sums=() #generate with 'makepkg -g' diff --git a/scripts/.gitignore b/scripts/.gitignore index 9e403bfb..26e088b9 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,4 +1,5 @@ makepkg +makepkg-template pacman-db-upgrade pacman-key pacman-optimize diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 784b1802..1f3bae24 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = po bin_SCRIPTS = \ $(OURSCRIPTS) \ + makepkg-template \ repo-remove \ repo-elephant @@ -18,6 +19,7 @@ OURSCRIPTS = \ EXTRA_DIST = \ makepkg.sh.in \ + makepkg-template.pl.in \ pacman-db-upgrade.sh.in \ pacman-key.sh.in \ pacman-optimize.sh.in \ @@ -54,6 +56,7 @@ edit = sed \ -e 's|@PACKAGE_BUGREPORT[@]|$(PACKAGE_BUGREPORT)|g' \ -e 's|@PACKAGE_NAME[@]|$(PACKAGE_NAME)|g' \ -e 's|@BUILDSCRIPT[@]|$(BUILDSCRIPT)|g' \ + -e 's|@TEMPLATE_DIR[@]|$(TEMPLATE_DIR)|g' \ -e 's|@DEBUGSUFFIX[@]|$(DEBUGSUFFIX)|g' \ -e "s|@INODECMD[@]|$(INODECMD)|g" \ -e 's|@SIZECMD[@]|$(SIZECMD)|g' \ @@ -76,6 +79,14 @@ makepkg: \ $(srcdir)/makepkg.sh.in \ $(srcdir)/library/parseopts.sh +makepkg-template: \ + $(srcdir)/makepkg-template.pl.in \ + Makefile + + $(AM_V_at)$(RM) -f makepkg-template + $(AM_V_GEN)$(edit) $< > $@ + $(AM_V_at)chmod +x,a-w $@ + pacman-db-upgrade: \ $(srcdir)/pacman-db-upgrade.sh.in \ $(srcdir)/library/output_format.sh diff --git a/scripts/makepkg-template.pl.in b/scripts/makepkg-template.pl.in new file mode 100755 index 00000000..567514e1 --- /dev/null +++ b/scripts/makepkg-template.pl.in @@ -0,0 +1,212 @@ +#!/usr/bin/perl +# makepkg-template - template system for makepkg +# @configure_input@ +# +# Copyright (c) 2013 Pacman Development Team <pacman-dev@archlinux.org> +# +# 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 2 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/>. +# +use warnings; +use strict; +use v5.10.1; +use Cwd qw(abs_path); +use Getopt::Long; +use Module::Load; +use Module::Load::Conditional qw(can_load); + +my %opts = ( + input => '@BUILDSCRIPT@', + template_dir => '@TEMPLATE_DIR@', +); + +my $template_name_charset = qr/[[:alnum:]+_.@-]/; +my $template_marker = qr/# template/; + +# runtime loading to avoid dependency on cpan since this is the only non-core module +my $loaded_gettext = can_load(modules => {'Locale::gettext' => undef}); +if ($loaded_gettext) { + Locale::gettext::bindtextdomain("pacman-scripts", '@localedir@'); + Locale::gettext::textdomain("pacman-scripts"); +} + +sub gettext { + my ($string) = @_; + + if ($loaded_gettext) { + return Locale::gettext::gettext($string); + } else { + return $string; + } +} + +sub burp { + my ($file_name, @lines) = @_; + open (my $fh, ">", $file_name) || die sprintf(gettext("can't create '%s': %s"), $file_name, $!); + print $fh @lines; + close $fh; +} + +# read a template marker line and parse values into a hash +# format is "# template (start|input); key=value; key2=value2; ..." +sub parse_template_line { + my ($line, $filename, $linenumber) = @_; + my %values; + + my ($marker, @elements) = split(/;\s?/, $line); + + ($values{command}) = ($marker =~ /$template_marker (.*)/); + + foreach my $element (@elements) { + my ($key, $val) = ($element =~ /^([a-z0-9]+)=(.*)$/); + unless ($key and $val) { + die gettext("invalid key/value pair\n%s:%s: %s"), + "$filename:$linenumber: $line"; + } + $values{$key} = $val; + } + + # end doesn't take arguments + if ($values{command} ne "end") { + if (!$values{name}) { + die gettext("invalid template line: can't find template name\n"), + "$filename:$linenumber: $line"; + } + + unless ($values{name} =~ /^$template_name_charset+$/) { + die sprintf(gettext("invalid chars used in name '%s'. allowed: [:alnum:]+_.\@-\n"), $values{name}), + "$filename:$linenumber: $line"; + } + } + + return \%values; +} + +# load a template, process possibly existing markers (nested templates) +sub load_template { + my ($values) = @_; + + my $ret = ""; + + my $path; + if (!$opts{newest} and $values->{version}) { + $path = "$opts{template_dir}/$values->{name}-$values->{version}.template"; + } else { + $path = "$opts{template_dir}/$values->{name}.template"; + } + + # resolve symlink(s) and use the real file's name for version detection + my ($version) = (abs_path($path) =~ /-([0-9.]+)[.]template$/); + + if (!$version) { + die sprintf(gettext("Couldn't detect version for template '%s'"), $values->{name}); + } + + my $parsed = process_file($path); + + $ret .= "# template start; name=$values->{name}; version=$version;\n"; + $ret .= $parsed; + $ret .= "# template end;\n"; + return $ret; +} + +# process input file and load templates for all markers found +sub process_file { + my ($filename) = @_; + + my $ret = ""; + my $nesting_level = 0; + my $linenumber = 0; + + open (my $fh, "<", $filename) or die sprintf(gettext("failed to open '%s': %s"), $filename, $!); + my @lines = <$fh>; + close $fh; + + foreach my $line (@lines) { + $linenumber++; + + if ($line =~ $template_marker) { + my $values = parse_template_line($line, $filename, $linenumber); + + if ($values->{command} eq "start" or $values->{command} eq "input") { + if ($nesting_level == 0) { + $ret .= load_template($values); + } + } elsif ($values->{command} eq "end") { + # nothing to do here, just for completeness + } else { + die sprintf(gettext("Unknown template marker '%s'\n"), $values->{command}), + "$filename:$linenumber: $line"; + } + + $nesting_level++ if $values->{command} eq "start"; + $nesting_level-- if $values->{command} eq "end"; + + # marker lines should never be added + next; + } + + # we replace code inside blocks with the template + # so we ignore the content of the block + next if $nesting_level > 0; + + $ret .= $line; + } + return $ret; +} + +sub usage { + my ($exitstatus) = @_; + print gettext("makepkg-template [options]\n"); + print "\n"; + print gettext("Options:\n"); + printf(gettext(" --input, -p <file> Build script to read (default: %s)\n"), '@BUILDSCRIPT@'); + print gettext(" --output, -o <file> file to output to (default: input file)\n"); + print gettext(" --newest, -n update templates to newest version\n"); + print gettext(" (default: use version specified in the template markers)\n"); + print gettext(" --template-dir <dir> directory to search for templates\n"); + printf(gettext(" (default: %s)\n"), '@TEMPLATE_DIR@'); + print gettext(" --help, -h This help message\n"); + print gettext(" --version Version information\n"); + print "\n"; + exit($exitstatus); +} + +sub version { + my ($exitstatus) = @_; + printf "makepkg-template (pacman) %s\n", '@PACKAGE_VERSION@'; + print gettext( + 'Copyright (c) 2013 Pacman Development Team <pacman-dev@archlinux.org>.'."\n". + 'This is free software; see the source for copying conditions.'."\n". + 'There is NO WARRANTY, to the extent permitted by law.'."\n"); + exit($exitstatus); +} + +Getopt::Long::Configure ("bundling"); +GetOptions( + "help|h" => sub {usage(0); }, + "version" => sub {version(0); }, + "input|p=s" => \$opts{input}, + "output|o=s" => \$opts{output}, + "newest|n" => \$opts{newest}, + "template-dir=s" => \$opts{template_dir}, +) or usage(1); + +$opts{output} = $opts{input} unless $opts{output}; + +$opts{input} = "/dev/stdin" if $opts{input} eq "-"; +$opts{output} = "/dev/stdout" if $opts{output} eq "-"; + +burp($opts{output}, process_file($opts{input})); + +# vim: set noet: diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 02f5a02d..2a391575 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -2095,6 +2095,10 @@ install_package() { fi } +have_function() { + declare -f "$1" >/dev/null +} + check_sanity() { # check for no-no's in the build script local i @@ -2240,9 +2244,14 @@ check_sanity() { ret=1 fi - if (( ${#pkgname[@]} > 1 )); then + if (( ${#pkgname[@]} == 1 )); then + if have_function build && ! ( have_function package || have_function package_${pkgname}); then + error "$(gettext "Missing %s function in %s")" "package()" "$BUILDFILE" + ret=1 + fi + else for i in ${pkgname[@]}; do - if ! declare -f package_${i} >/dev/null; then + if ! have_function package_${i}; then error "$(gettext "Missing %s function for split package '%s'")" "package_$i()" "$i" ret=1 fi @@ -2510,6 +2519,7 @@ usage() { printf -- "$(gettext " --holdver Do not update VCS sources")\n" printf -- "$(gettext " --key <key> Specify a key to use for %s signing instead of the default")\n" "gpg" printf -- "$(gettext " --nocheck Do not run the %s function in the %s")\n" "check()" "$BUILDSCRIPT" + printf -- "$(gettext " --noprepare Do not run the %s function in the %s")\n" "prepare()" "$BUILDSCRIPT" printf -- "$(gettext " --nosign Do not create a signature for the package")\n" printf -- "$(gettext " --pkg <list> Only build listed packages from a split package")\n" printf -- "$(gettext " --sign Sign the resulting package with %s")\n" "gpg" @@ -2552,7 +2562,7 @@ ARGLIST=("$@") OPT_SHORT="AcdefFghiLmop:rRsSV" OPT_LONG=('allsource' 'asroot' 'check' 'clean' 'config:' 'force' 'geninteg' 'help' 'holdver' 'ignorearch' 'install' 'key:' 'log' 'nobuild' 'nocolor' - 'nocheck' 'nodeps' 'noextract' 'nosign' 'pkg:' 'repackage' 'rmdeps' + 'nocheck' 'nodeps' 'noextract' 'noprepare' 'nosign' 'pkg:' 'repackage' 'rmdeps' 'sign' 'skipchecksums' 'skipinteg' 'skippgpcheck' 'source' 'syncdeps' 'verifysource' 'version') @@ -2591,6 +2601,7 @@ while true; do -L|--log) LOGGING=1 ;; -m|--nocolor) USE_COLOR='n' ;; --nocheck) RUN_CHECK='n' ;; + --noprepare) RUN_PREPARE='n' ;; --nosign) SIGNPKG='n' ;; -o|--nobuild) NOBUILD=1 ;; -p) shift; BUILDFILE=$1 ;; @@ -2631,6 +2642,7 @@ trap 'trap_exit USR1 "$(gettext "An unknown error has occurred. Exiting...")"' E [[ -n ${SRCEXT} ]] && _SRCEXT=${SRCEXT} [[ -n ${GPGKEY} ]] && _GPGKEY=${GPGKEY} [[ -n ${PACKAGER} ]] && _PACKAGER=${PACKAGER} +[[ -n ${CARCH} ]] && _CARCH=${CARCH} # default config is makepkg.conf MAKEPKG_CONF=${MAKEPKG_CONF:-$confdir/makepkg.conf} @@ -2667,12 +2679,12 @@ if [[ -t 2 && ! $USE_COLOR = "n" ]] && check_buildenv "color" "y"; then RED="${BOLD}$(tput setaf 1)" YELLOW="${BOLD}$(tput setaf 3)" else - ALL_OFF="\e[1;0m" - BOLD="\e[1;1m" - BLUE="${BOLD}\e[1;34m" - GREEN="${BOLD}\e[1;32m" - RED="${BOLD}\e[1;31m" - YELLOW="${BOLD}\e[1;33m" + ALL_OFF="\e[0m" + BOLD="\e[1m" + BLUE="${BOLD}\e[34m" + GREEN="${BOLD}\e[32m" + RED="${BOLD}\e[31m" + YELLOW="${BOLD}\e[33m" fi fi readonly ALL_OFF BOLD BLUE GREEN RED YELLOW @@ -2730,6 +2742,7 @@ PKGEXT=${_PKGEXT:-$PKGEXT} SRCEXT=${_SRCEXT:-$SRCEXT} GPGKEY=${_GPGKEY:-$GPGKEY} PACKAGER=${_PACKAGER:-$PACKAGER} +CARCH=${_CARCH:-$CARCH} if (( ! INFAKEROOT )); then if (( EUID == 0 && ! ASROOT )); then @@ -2762,17 +2775,10 @@ unset makedepends optdepends options noextract BUILDFILE=${BUILDFILE:-$BUILDSCRIPT} if [[ ! -f $BUILDFILE ]]; then - if [[ -t 0 ]]; then - error "$(gettext "%s does not exist.")" "$BUILDFILE" - exit 1 - else - # PKGBUILD passed through a pipe - BUILDFILE=/dev/stdin - source_safe "$BUILDFILE" - fi + error "$(gettext "%s does not exist.")" "$BUILDFILE" + exit 1 else - crlftest=$(file "$BUILDFILE" | grep -F 'CRLF' || true) - if [[ -n $crlftest ]]; then + if [[ $(<"$BUILDFILE") = *$'\r'* ]]; then error "$(gettext "%s contains %s characters and cannot be sourced.")" "$BUILDFILE" "CRLF" exit 1 fi @@ -2808,7 +2814,7 @@ if (( GENINTEG )); then exit 0 # $E_OK fi -if declare -f pkgver >/dev/null; then +if have_function pkgver; then PKGVERFUNC=1 fi @@ -2823,21 +2829,24 @@ if (( ${#pkgname[@]} > 1 )); then fi # test for available PKGBUILD functions -if declare -f prepare >/dev/null; then - PREPAREFUNC=1 +if have_function prepare; then + # "Hide" prepare() function if not going to be run + if [[ $RUN_PREPARE != "n" ]]; then + PREPAREFUNC=1 + fi fi -if declare -f build >/dev/null; then +if have_function build; then BUILDFUNC=1 fi -if declare -f check >/dev/null; then +if have_function check; then # "Hide" check() function if not going to be run if [[ $RUN_CHECK = 'y' ]] || { ! check_buildenv "check" "n" && [[ $RUN_CHECK != "n" ]]; }; then CHECKFUNC=1 fi fi -if declare -f package >/dev/null; then +if have_function package; then PKGFUNC=1 -elif [[ $SPLITPKG -eq 0 ]] && declare -f package_${pkgname} >/dev/null; then +elif [[ $SPLITPKG -eq 0 ]] && have_function package_${pkgname}; then SPLITPKG=1 fi @@ -2875,17 +2884,7 @@ if (( INFAKEROOT )); then if (( ! SPLITPKG )); then pkgdir="$pkgdirbase/$pkgname" mkdir "$pkgdir" - if (( ! PKGFUNC )); then - if (( ! REPKG )); then - if (( BUILDFUNC )); then - run_build - (( CHECKFUNC )) && run_check - fi - else - warning "$(gettext "Repackaging without the use of a %s function is deprecated.")" "package()" - plain "$(gettext "File permissions may not be preserved.")" - fi - else + if (( PKGFUNC )); then run_package fi tidy_install @@ -2902,10 +2901,6 @@ fi fullver=$(get_full_version) msg "$(gettext "Making package: %s")" "$pkgbase $fullver ($(date))" -if (( !PKGFUNC && !SPLITPKG )); then - warning "$(gettext "Using a %s without a %s function is deprecated.")" "$BUILDSCRIPT" "package()" -fi - # if we are creating a source-only package, go no further if (( SOURCEONLY )); then if [[ -f $SRCPKGDEST/${pkgbase}-${fullver}${SRCEXT} ]] \ @@ -2983,14 +2978,7 @@ cd_safe "$srcdir" if (( NOEXTRACT && ! VERIFYSOURCE )); then warning "$(gettext "Using existing %s tree")" "src/" -elif (( REPKG )); then - if (( ! PKGFUNC && ! SPLITPKG )) \ - && { [[ ! -d $pkgdirbase ]] || dir_is_empty "$pkgdirbase"; }; then - error "$(gettext "The package directory is empty, there is nothing to repackage!")" - plain "$(gettext "Aborting...")" - exit 1 - fi -else +elif (( !REPKG )); then download_sources check_source_integrity (( VERIFYSOURCE )) && exit 0 # $E_OK @@ -3004,8 +2992,8 @@ if (( NOBUILD )); then msg "$(gettext "Sources are ready.")" exit 0 #E_OK else - # check for existing pkg directory; don't remove if we are repackaging - if [[ -d $pkgdirbase ]] && (( ! REPKG || PKGFUNC || SPLITPKG )); then + # clean existing pkg directory + if [[ -d $pkgdirbase ]]; then msg "$(gettext "Removing existing %s directory...")" "pkg/" rm -rf "$pkgdirbase" fi @@ -3029,9 +3017,6 @@ else mkdir -p "$pkgdir" if (( PKGFUNC )); then run_package - elif (( REPKG )); then - warning "$(gettext "Repackaging without the use of a %s function is deprecated.")" "package()" - plain "$(gettext "File permissions may not be preserved.")" fi tidy_install create_package @@ -3040,7 +3025,7 @@ else run_split_packaging fi else - if (( ! REPKG && ( PKGFUNC || SPLITPKG ) )); then + if (( ! REPKG )); then (( BUILDFUNC )) && run_build (( CHECKFUNC )) && run_check cd_safe "$startdir" diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index 162731b9..f9e8a481 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -2,6 +2,7 @@ # scripts with gettext translations scripts/makepkg.sh.in +scripts/makepkg-template.pl.in scripts/pacman-db-upgrade.sh.in scripts/pacman-key.sh.in scripts/pacman-optimize.sh.in diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 4470dd0a..a9a4499b 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -31,6 +31,7 @@ declare -r confdir='@sysconfdir@' QUIET=0 DELTA=0 ONLYADDNEW=0 +RMEXISTING=0 WITHFILES=0 SIGN=0 VERIFY=0 @@ -58,6 +59,7 @@ Multiple packages to add can be specified on the command line.\n")" printf -- "$(gettext "Options:\n")" printf -- "$(gettext " -d, --delta generate and add delta for package update\n")" printf -- "$(gettext " -n, --new only add packages that are not already in the database\n")" + printf -- "$(gettext " -R, --remove remove package file from disk when updating database entry\n")" printf -- "$(gettext " -f, --files update database's file list\n")" elif [[ $cmd == "repo-remove" ]] ; then printf -- "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n")" @@ -304,6 +306,15 @@ db_write_entry() { local oldfilename=$(grep -A1 FILENAME "$pkgentry/desc" | tail -n1) local oldfile="$(dirname "$1")/$oldfilename" fi + elif (( RMEXISTING )); then + # only remove existing package if we're not doing deltas + pkgentry=$(find_pkgentry "$pkgname") + if [[ -n $pkgentry ]]; then + local oldfilename="$(sed -n '/^%FILENAME%$/ {n;p;q;}' "$pkgentry/desc")" + local oldfile="$(dirname "$1")/$oldfilename" + msg2 "$(gettext "Removing existing package '%s'")" "$oldfilename" + rm -f ${oldfile} ${oldfile}.sig + fi fi fi @@ -611,6 +622,7 @@ while (( $# )); do -q|--quiet) QUIET=1;; -d|--delta) DELTA=1;; -n|--new) ONLYADDNEW=1;; + -R|--remove) RMEXISTING=1;; -f|--files) WITHFILES=1;; --nocolor) USE_COLOR='n';; -s|--sign) diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 12c80d36..c57ef34a 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -309,6 +309,11 @@ void cb_question(alpm_question_t event, void *data1, void *data2, void *data3, int *response) { if(config->print) { + if(event == ALPM_QUESTION_INSTALL_IGNOREPKG) { + *response = 1; + } else { + *response = 0; + } return; } switch(event) { @@ -377,15 +382,6 @@ void cb_question(alpm_question_t event, void *data1, void *data2, *response = select_question(count); } break; - case ALPM_QUESTION_LOCAL_NEWER: - if(!config->op_s_downloadonly) { - *response = yesno(_("%s-%s: local version is newer. Upgrade anyway?"), - alpm_pkg_get_name(data1), - alpm_pkg_get_version(data1)); - } else { - *response = 1; - } - break; case ALPM_QUESTION_CORRUPTED_PKG: *response = yesno(_("File %s is corrupted (%s).\n" "Do you want to delete it?"), diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 921331c6..7aa0271c 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -826,6 +826,7 @@ int main(int argc, char *argv[]) /* we support reading targets from stdin if a cmdline parameter is '-' */ if(alpm_list_find_str(pm_targets, "-")) { if(!isatty(fileno(stdin))) { + int target_found = 0; size_t current_size = PATH_MAX; char *vdata, *line = malloc(current_size); @@ -840,6 +841,7 @@ int main(int argc, char *argv[]) if(i > 0) { line[i] = '\0'; pm_targets = alpm_list_add(pm_targets, strdup(line)); + target_found = 1; i = 0; } } else { @@ -869,12 +871,18 @@ int main(int argc, char *argv[]) if(i > 0) { line[i] = '\0'; pm_targets = alpm_list_add(pm_targets, strdup(line)); + target_found = 1; } free(line); if(!freopen(ctermid(NULL), "r", stdin)) { pm_printf(ALPM_LOG_ERROR, _("failed to reopen stdin for reading: (%s)\n"), strerror(errno)); } + + if(!target_found) { + pm_printf(ALPM_LOG_ERROR, _("argument '-' specified with empty stdin\n")); + cleanup(1); + } } else { /* do not read stdin from terminal */ pm_printf(ALPM_LOG_ERROR, _("argument '-' specified without input on stdin\n")); diff --git a/src/pacman/query.c b/src/pacman/query.c index f051571c..f5862a2d 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -90,6 +90,49 @@ static void print_query_fileowner(const char *filename, alpm_pkg_t *info) } } +/** Resolve the canonicalized absolute path of a symlink. + * @param path path to resolve + * @param resolved_path destination for the resolved path, will be malloc'd if + * NULL + * @return the resolved path + */ +static char *lrealpath(const char *path, char *resolved_path) +{ + const char *bname = mbasename(path); + char *rpath = NULL, *dname = NULL; + int success = 0; + + if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { + /* the entire path needs to be resolved */ + return realpath(path, resolved_path); + } + + if(!(dname = mdirname(path))) { + goto cleanup; + } + if(!(rpath = realpath(dname, NULL))) { + goto cleanup; + } + if(!resolved_path) { + if(!(resolved_path = malloc(strlen(rpath) + strlen(bname) + 2))) { + goto cleanup; + } + } + + strcpy(resolved_path, rpath); + if(resolved_path[strlen(resolved_path) - 1] != '/') { + strcat(resolved_path, "/"); + } + strcat(resolved_path, bname); + success = 1; + +cleanup: + free(dname); + free(rpath); + + return (success ? resolved_path : NULL); +} + static int query_fileowner(alpm_list_t *targets) { int ret = 0; @@ -133,11 +176,11 @@ static int query_fileowner(alpm_list_t *targets) packages = alpm_db_get_pkgcache(db_local); for(t = targets; t; t = alpm_list_next(t)) { - char *filename = NULL, *dname = NULL, *rpath = NULL; - const char *bname; + char *filename = NULL; + char rpath[PATH_MAX], *rel_path; struct stat buf; alpm_list_t *i; - size_t len, is_dir, bname_len, pbname_len; + size_t len, is_dir; unsigned int found = 0; if((filename = strdup(t->data)) == NULL) { @@ -165,82 +208,32 @@ static int query_fileowner(alpm_list_t *targets) } } - is_dir = S_ISDIR(buf.st_mode) ? 1 : 0; - if(is_dir) { - /* the entire filename is safe to resolve if we know it points to a dir, - * and it's necessary in case it ends in . or .. */ - dname = realpath(filename, NULL); - bname = mbasename(dname); - rpath = mdirname(dname); - } else { - bname = mbasename(filename); - dname = mdirname(filename); - rpath = realpath(dname, NULL); - } - - bname_len = strlen(bname); - pbname_len = bname_len + is_dir; - - if(!dname || !rpath) { + if(!lrealpath(filename, rpath)) { pm_printf(ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), filename, strerror(errno)); goto targcleanup; } - for(i = packages; i && (!found || is_dir); i = alpm_list_next(i)) { - alpm_pkg_t *info = i->data; - alpm_filelist_t *filelist = alpm_pkg_get_files(info); - size_t j; - - for(j = 0; j < filelist->count; j++) { - const alpm_file_t *file = filelist->files + j; - char *ppath; - const char *pkgfile = file->name; - size_t pkgfile_len = strlen(pkgfile); - - /* make sure pkgfile and target are of the same type */ - if(is_dir != (pkgfile[pkgfile_len - 1] == '/')) { - continue; - } - - /* make sure pkgfile is long enough */ - if(pkgfile_len < pbname_len) { - continue; - } - - /* make sure pbname_len takes us to the start of a path component */ - if(pbname_len != pkgfile_len && pkgfile[pkgfile_len - pbname_len - 1] != '/') { - continue; - } + if(strncmp(rpath, path, rootlen) != 0) { + /* file is outside root, we know nothing can own it */ + pm_printf(ALPM_LOG_ERROR, _("No package owns %s\n"), filename); + goto targcleanup; + } - /* compare basename with bname */ - if(strncmp(pkgfile + pkgfile_len - pbname_len, bname, bname_len) != 0) { - continue; - } + rel_path = rpath + rootlen; - /* concatenate our dirname and the root path */ - if(rootlen + 1 + pkgfile_len - pbname_len > PATH_MAX) { - path[rootlen] = '\0'; /* reset path for error message */ - pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), path, pkgfile); - continue; - } - strncpy(path + rootlen, pkgfile, pkgfile_len - pbname_len); - path[rootlen + pkgfile_len - pbname_len] = '\0'; - - ppath = realpath(path, NULL); - if(!ppath) { - pm_printf(ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), - path, strerror(errno)); - continue; - } + if((is_dir = S_ISDIR(buf.st_mode))) { + size_t rlen = strlen(rpath); + if(rlen + 2 >= PATH_MAX) { + pm_printf(ALPM_LOG_ERROR, _("path too long: %s/\n"), rpath); + } + strcat(rpath + rlen, "/"); + } - if(strcmp(ppath, rpath) == 0) { - print_query_fileowner(filename, info); - found = 1; - free(ppath); - break; - } - free(ppath); + for(i = packages; i && (!found || is_dir); i = alpm_list_next(i)) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), rel_path)) { + print_query_fileowner(rpath, i->data); + found = 1; } } if(!found) { @@ -252,8 +245,6 @@ targcleanup: ret++; } free(filename); - free(rpath); - free(dname); } return ret; diff --git a/src/pacman/sync.c b/src/pacman/sync.c index e8da3460..20930290 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -238,9 +238,7 @@ static int sync_cleancache(int level) /* skip source packages within the cache directory */ "*.src.tar.*", /* skip package deltas, we aren't smart enough to clean these yet */ - "*.delta", - /* skip any partial downloads */ - "*.part" + "*.delta" }; size_t j; diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py index 988c73f3..9b3147a3 100644 --- a/test/pacman/pmpkg.py +++ b/test/pacman/pmpkg.py @@ -160,6 +160,8 @@ class pmpkg(object): info = tarfile.TarInfo(fileinfo["filename"]) if fileinfo["hasperms"]: info.mode = fileinfo["perms"] + elif fileinfo["isdir"]: + info.mode = 0755 if fileinfo["isdir"]: info.type = tarfile.DIRTYPE tar.addfile(info) diff --git a/test/pacman/pmtest.py b/test/pacman/pmtest.py index 2eafe682..f5a96805 100644 --- a/test/pacman/pmtest.py +++ b/test/pacman/pmtest.py @@ -241,7 +241,7 @@ class pmtest(object): # archives are made available more easily. time_start = time.time() self.retcode = subprocess.call(cmd, stdout=output, stderr=output, - cwd=os.path.join(self.root, util.TMPDIR)) + cwd=os.path.join(self.root, util.TMPDIR), env={'LC_ALL': 'C'}) time_end = time.time() vprint("\ttime elapsed: %.2fs" % (time_end - time_start)) diff --git a/test/pacman/tests/fileconflict007.py b/test/pacman/tests/fileconflict007.py index 4ee4624e..7fe65ed4 100644 --- a/test/pacman/tests/fileconflict007.py +++ b/test/pacman/tests/fileconflict007.py @@ -15,3 +15,4 @@ self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=pkg") self.addrule("PKG_VERSION=pkg|1.0-2") +self.addrule("FILE_TYPE=dir/symdir/|dir") diff --git a/test/pacman/tests/fileconflict013.py b/test/pacman/tests/fileconflict013.py index a83923c6..aacb730a 100644 --- a/test/pacman/tests/fileconflict013.py +++ b/test/pacman/tests/fileconflict013.py @@ -1,4 +1,5 @@ self.description = "file->file path change with same effective path (/lib as symlink)" +# Note: this situation means the filesystem and local db are out of sync lp1 = pmpkg("filesystem", "1.0-1") lp1.files = ["usr/", @@ -16,5 +17,5 @@ self.addpkg2db("sync", sp1) self.args = "-Su" -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=pkg1|1.0-2") +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") diff --git a/test/pacman/tests/fileconflict022.py b/test/pacman/tests/fileconflict022.py index 5759d4c3..5ff0b537 100644 --- a/test/pacman/tests/fileconflict022.py +++ b/test/pacman/tests/fileconflict022.py @@ -14,6 +14,5 @@ self.addpkg2db("sync", sp2) self.args = "-S %s %s" % (sp1.name, sp2.name) self.addrule("PACMAN_RETCODE=1") -self.addrule("PACMAN_OUTPUT=.*/usr/lib/file exists in both 'foo' and 'bar'") self.addrule("!PKG_EXIST=foo") self.addrule("!PKG_EXIST=bar") diff --git a/test/pacman/tests/fileconflict023.py b/test/pacman/tests/fileconflict023.py index ce72087b..1a7eaaf7 100644 --- a/test/pacman/tests/fileconflict023.py +++ b/test/pacman/tests/fileconflict023.py @@ -1,4 +1,5 @@ self.description = "File conflict between package with symlink and package with real path resolved by removal" +# Note: this situation means the filesystem and local db are out of sync self.filesystem = ["usr/", "usr/lib/", "lib -> usr/lib/"] @@ -13,6 +14,6 @@ self.addpkg2db("sync", sp1) self.args = "-S %s --ask=4" % sp1.name -self.addrule("PACMAN_RETCODE=0") -self.addrule("!PKG_EXIST=foo") -self.addrule("PKG_EXIST=bar") +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_EXIST=foo") +self.addrule("!PKG_EXIST=bar") diff --git a/test/pacman/tests/fileconflict025.py b/test/pacman/tests/fileconflict025.py index 3c6f0638..263c81d4 100644 --- a/test/pacman/tests/fileconflict025.py +++ b/test/pacman/tests/fileconflict025.py @@ -1,4 +1,4 @@ -self.description = "File conflict between package with symlink and package with real path resolved by removal (reversed)" +self.description = "File conflict between package with symlink and package with real path and filesystem (reversed)" self.filesystem = ["usr/lib/", "lib -> usr/lib/"] @@ -13,6 +13,6 @@ self.addpkg2db("sync", sp1) self.args = "-S %s --ask=4" % sp1.name -self.addrule("PACMAN_RETCODE=0") -self.addrule("!PKG_EXIST=foo") -self.addrule("PKG_EXIST=bar") +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_EXIST=foo") +self.addrule("!PKG_EXIST=bar") diff --git a/test/pacman/tests/fileconflict030.py b/test/pacman/tests/fileconflict030.py new file mode 100644 index 00000000..1de77813 --- /dev/null +++ b/test/pacman/tests/fileconflict030.py @@ -0,0 +1,17 @@ +self.description = "Dir->file transition filesystem conflict resolved by removal" + +lp1 = pmpkg("foo") +lp1.files = ["foo/"] +self.addpkg2db("local", lp1) + +sp1 = pmpkg("bar") +sp1.conflicts = ["foo"] +sp1.files = ["foo"] +self.addpkg2db("sync", sp1) + +self.args = "-S %s --ask=4" % sp1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_EXIST=bar") +self.addrule("!PKG_EXIST=foo") +self.addrule("FILE_EXIST=foo") diff --git a/test/pacman/tests/ignore005.py b/test/pacman/tests/ignore005.py index 274e44c3..51bcba39 100644 --- a/test/pacman/tests/ignore005.py +++ b/test/pacman/tests/ignore005.py @@ -36,7 +36,7 @@ self.addpkg2db("sync", packageA5up) self.option["IgnorePkg"] = ["packageA3"] -self.args = "-S packageA1 packageA2 --ask=32" +self.args = "-S packageA1 packageA2 --ask=16" self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_VERSION=packageA1|1.0-1") diff --git a/test/pacman/tests/symlink001.py b/test/pacman/tests/symlink001.py index cbf71ccc..91365512 100644 --- a/test/pacman/tests/symlink001.py +++ b/test/pacman/tests/symlink001.py @@ -11,10 +11,9 @@ self.addpkg(p) self.args = "-U %s" % p.filename() -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_EXIST=pkg1") -self.addrule("FILE_EXIST=dir/symdir/tmp") -self.addrule("FILE_EXIST=dir/realdir/tmp") -self.addrule("FILE_TYPE=dir/symdir/tmp|file") +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!FILE_EXIST=dir/symdir/tmp") +self.addrule("!FILE_EXIST=dir/realdir/tmp") self.addrule("FILE_TYPE=dir/symdir|link") self.addrule("FILE_TYPE=dir/realdir|dir") diff --git a/test/pacman/tests/symlink020.py b/test/pacman/tests/symlink020.py new file mode 100644 index 00000000..343add2d --- /dev/null +++ b/test/pacman/tests/symlink020.py @@ -0,0 +1,20 @@ +self.description = "symlink -> dir replacment" + +lp1 = pmpkg("pkg1") +lp1.files = ["usr/lib/foo", + "lib -> usr/lib/"] +self.addpkg2db("local", lp1) + +lp1 = pmpkg("pkg2") +lp1.files = ["usr/lib/bar"] +self.addpkg2db("local", lp1) + +sp = pmpkg("pkg1", "1.0-2") +sp.files = ["lib/bar"] +self.addpkg2db("sync", sp) + +self.args = "-S %s" % sp.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("FILE_TYPE=lib|dir") +self.addrule("FILE_TYPE=lib/bar|file") diff --git a/test/pacman/tests/sync140.py b/test/pacman/tests/sync140.py index ce21cc33..fbe750f2 100644 --- a/test/pacman/tests/sync140.py +++ b/test/pacman/tests/sync140.py @@ -18,7 +18,7 @@ sp3.depends = ["gcc-libs"] for p in sp1, sp2, sp3: self.addpkg2db("sync", p) -self.args = "-Su --ignore %s --ask=32" % sp1.name +self.args = "-Su --ignore %s --ask=16" % sp1.name self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_VERSION=glibc|1.0-1") diff --git a/test/pacman/tests/sync141.py b/test/pacman/tests/sync141.py index f2f01364..02f7be81 100644 --- a/test/pacman/tests/sync141.py +++ b/test/pacman/tests/sync141.py @@ -18,7 +18,7 @@ sp3.depends = ["b_gcc-libs"] for p in sp1, sp2, sp3: self.addpkg2db("sync", p) -self.args = "-Su --ignore %s --ask=32" % sp1.name +self.args = "-Su --ignore %s --ask=16" % sp1.name self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_VERSION=c_glibc|1.0-1") diff --git a/test/pacman/tests/sync700.py b/test/pacman/tests/sync700.py index 9748c819..3948b006 100644 --- a/test/pacman/tests/sync700.py +++ b/test/pacman/tests/sync700.py @@ -1,4 +1,5 @@ -self.description = "do not remove directory symlink if another package has file in its path" +self.description = "removal of directory symlink when another package has file in its path" +# Note: this situation means that the filesystem and local db are out of sync lp1 = pmpkg("pkg1") lp1.files = ["usr/lib/foo", @@ -15,8 +16,7 @@ self.addpkg2db("sync", p) self.args = "-S pkg1" -self.addrule("PACMAN_RETCODE=1") -self.addrule("PKG_VERSION=pkg1|1.0-1") -self.addrule("FILE_EXIST=lib/bar") - -self.expectfailure = True +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-2") +self.addrule("FILE_EXIST=usr/lib/bar") +self.addrule("!FILE_EXIST=lib/bar") diff --git a/test/pacman/tests/sync701.py b/test/pacman/tests/sync701.py index 201f6028..590845ff 100644 --- a/test/pacman/tests/sync701.py +++ b/test/pacman/tests/sync701.py @@ -1,4 +1,4 @@ -self.description = "do not remove directory symlink if incoming package has file in its path (order 1)" +self.description = "incoming package replaces symlink with directory (order 1)" lp = pmpkg("pkg1") lp.files = ["usr/lib/foo", @@ -15,8 +15,7 @@ self.addpkg2db("sync", p2) self.args = "-S pkg1 pkg2" -self.addrule("PACMAN_RETCODE=1") -self.addrule("PKG_VERSION=pkg1|1.0-1") -self.addrule("!PKG_EXIST=pkg2") - -self.expectfailure = True +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-2") +self.addrule("PKG_EXIST=pkg2") +self.addrule("FILE_TYPE=lib|dir") diff --git a/test/pacman/tests/sync702.py b/test/pacman/tests/sync702.py index ee4eef95..c3e2320a 100644 --- a/test/pacman/tests/sync702.py +++ b/test/pacman/tests/sync702.py @@ -1,4 +1,4 @@ -self.description = "do not remove directory symlink if incoming package has file in its path (order 2)" +self.description = "incoming package replaces symlink with directory (order 2)" lp = pmpkg("pkg2") lp.files = ["usr/lib/foo", @@ -15,8 +15,7 @@ self.addpkg2db("sync", p2) self.args = "-S pkg1 pkg2" -self.addrule("PACMAN_RETCODE=1") -self.addrule("PKG_VERSION=pkg2|1.0-1") -self.addrule("!PKG_EXIST=pkg1") - -self.expectfailure = True +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg2|1.0-2") +self.addrule("PKG_EXIST=pkg1") +self.addrule("FILE_TYPE=lib|dir") diff --git a/test/pacman/tests/unresolvable001.py b/test/pacman/tests/unresolvable001.py index 9d54c3e5..4e5da6f3 100644 --- a/test/pacman/tests/unresolvable001.py +++ b/test/pacman/tests/unresolvable001.py @@ -11,7 +11,7 @@ packageA2up = pmpkg("package") packageA2up.depends = ["dep"]; self.addpkg2db("sync", packageA2up) -self.args = "-S package dep --ask=32" +self.args = "-S package dep --ask=16" self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=package") diff --git a/test/pacman/tests/upgrade045.py b/test/pacman/tests/upgrade045.py index 3b7f4769..c909aa08 100644 --- a/test/pacman/tests/upgrade045.py +++ b/test/pacman/tests/upgrade045.py @@ -14,4 +14,5 @@ self.args = "-U %s" % p1.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_VERSION=foo|1.0-2") -self.addrule("FILE_EXIST=etc/foo.cfg") +self.addrule("LINK_EXIST=etc/foo.cfg") +self.addrule("FILE_EXIST=etc/foo.cfg.pacnew") diff --git a/test/pacman/tests/upgrade090.py b/test/pacman/tests/upgrade090.py index 26e531c9..cdd4cace 100644 --- a/test/pacman/tests/upgrade090.py +++ b/test/pacman/tests/upgrade090.py @@ -16,7 +16,7 @@ sp = pmpkg("dep") sp.files = ["bin/dep"] self.addpkg2db("sync", sp) -self.args = "-U %s --ask=32" % " ".join([p.filename() for p in p1, p2, p3]) +self.args = "-U %s --ask=16" % " ".join([p.filename() for p in p1, p2, p3]) self.addrule("PACMAN_RETCODE=0") for p in p1, p2, sp: diff --git a/test/pacman/util.py b/test/pacman/util.py index be99cd57..65540ed3 100644 --- a/test/pacman/util.py +++ b/test/pacman/util.py @@ -100,7 +100,7 @@ def mkfile(base, name, data=""): def writedata(filename, data): if isinstance(data, list): data = "\n".join(data) - fd = file(filename, "w") + fd = open(filename, "w") if data: fd.write(data) if data[-1] != "\n": diff --git a/test/scripts/parseopts_test.sh b/test/scripts/parseopts_test.sh index 2862caec..b7e5d08a 100755 --- a/test/scripts/parseopts_test.sh +++ b/test/scripts/parseopts_test.sh @@ -18,7 +18,7 @@ fi OPT_SHORT="AcdefFghiLmop:rRsV" OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean:' 'cleanall' 'nodeps' 'noextract' 'force' 'forcever:' 'geninteg' 'help' 'holdver' - 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'nosign' 'pkg:' 'rmdeps' + 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'noprepare' 'nosign' 'pkg:' 'rmdeps' 'repackage' 'skipinteg' 'sign' 'source' 'syncdeps' 'version' 'config:' 'noconfirm' 'noprogressbar') |