[pacman-dev] [PATCH 1/3] Add Architecture and --arch option
--- doc/pacman.8.txt | 2 ++ doc/pacman.conf.5.txt | 8 ++++++++ etc/pacman.conf.in | 1 + lib/libalpm/alpm.h | 3 +++ lib/libalpm/handle.c | 16 ++++++++++++++++ lib/libalpm/handle.h | 1 + src/pacman/pacman.c | 22 ++++++++++++++++++++++ 7 files changed, 53 insertions(+), 0 deletions(-) diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index b288a59..a534e05 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -166,6 +166,8 @@ Options If an install scriptlet exists, do not execute it. Do not use this unless you know what you are doing. +*\--arch* <'arch'>:: + Specify an alternate architecture. Query Options[[QO]] ------------------- diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 46a0b3d..51c5188 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -150,6 +150,14 @@ Options than the percent of each individual download target. The progress bar is still based solely on the current file download. +*Architecture =* auto | i686 | x86_64 | ...:: + If set, pacman will only allow to install packages of the given + architecture (e.g. 'i686', 'x86_64', etc). The special value 'auto' will + use the system architecture, as in 'uname -m'. + If unset, no architecture checks are made. + *NOTE*: the packages with the special architecture 'any' can always be + installed, as they are meant to be architecture independent. + Repository Sections ------------------- Each repository section defines a section name and at least one location where diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 3557274..929d38b 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -19,6 +19,7 @@ SyncFirst = pacman #XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u #XferCommand = /usr/bin/curl %u > %o #CleanMethod = KeepInstalled +Architecture = auto # Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup #IgnorePkg = diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 9a935c2..b81b3f8 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -151,6 +151,9 @@ void alpm_option_add_ignoregrp(const char *grp); void alpm_option_set_ignoregrps(alpm_list_t *ignoregrps); int alpm_option_remove_ignoregrp(const char *grp); +const char *alpm_option_get_arch(); +void alpm_option_set_arch(const char *arch); + void alpm_option_set_usedelta(unsigned short usedelta); pmdb_t *alpm_option_get_localdb(); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 819b974..012d412 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -79,6 +79,7 @@ void _alpm_handle_free(pmhandle_t *handle) FREELIST(handle->cachedirs); FREE(handle->logfile); FREE(handle->lockfile); + FREE(handle->arch); FREELIST(handle->dbs_sync); FREELIST(handle->noupgrade); FREELIST(handle->noextract); @@ -213,6 +214,15 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregrps() return handle->ignoregrp; } +const char SYMEXPORT *alpm_option_get_arch() +{ + if (handle == NULL) { + pm_errno = PM_ERR_HANDLE_NULL; + return NULL; + } + return handle->arch; +} + pmdb_t SYMEXPORT *alpm_option_get_localdb() { if (handle == NULL) { @@ -520,6 +530,12 @@ int SYMEXPORT alpm_option_remove_ignoregrp(const char *grp) return(0); } +void SYMEXPORT alpm_option_set_arch(const char *arch) +{ + if(handle->arch) FREE(handle->arch); + if(arch) handle->arch = strdup(arch); +} + void SYMEXPORT alpm_option_set_usedelta(unsigned short usedelta) { handle->usedelta = usedelta; diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 541eb23..a1eb1cd 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -58,6 +58,7 @@ typedef struct _pmhandle_t { /* options */ unsigned short usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ + char *arch; /* Architecture of packages we should allow */ unsigned short usedelta; /* Download deltas if possible */ } pmhandle_t; diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 25647b5..5fab247 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -149,6 +149,7 @@ static void usage(int op, const char * const myname) printf(_(" -r, --root <path> set an alternate installation root\n")); printf(_(" -b, --dbpath <path> set an alternate database location\n")); printf(_(" --cachedir <dir> set an alternate package cache location\n")); + printf(_(" --arch <arch> set an alternate architecture\n")); } } @@ -195,6 +196,19 @@ static void setuseragent(void) setenv("HTTP_USER_AGENT", agent, 0); } +static void setarch(const char *arch) +{ + if (strcmp(arch, "auto") == 0) { + struct utsname un; + uname(&un); + pm_printf(PM_LOG_DEBUG, "config: architecture: %s\n", un.machine); + alpm_option_set_arch(un.machine); + } else { + pm_printf(PM_LOG_DEBUG, "config: architecture: %s\n", arch); + alpm_option_set_arch(arch); + } +} + /** Free the resources. * * @param ret the return value @@ -376,6 +390,7 @@ static int parseargs(int argc, char *argv[]) {"ignoregroup", required_argument, 0, 1010}, {"needed", no_argument, 0, 1011}, {"asexplicit", no_argument, 0, 1012}, + {"arch", required_argument, 0, 1013}, {0, 0, 0, 0} }; @@ -450,6 +465,9 @@ static int parseargs(int argc, char *argv[]) case 1012: config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; break; + case 1013: + setarch(optarg); + break; case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; @@ -827,6 +845,10 @@ static int _parseconfig(const char *file, const char *givensection, setrepeatingoption(ptr, "HoldPkg", option_add_holdpkg); } else if(strcmp(key, "SyncFirst") == 0) { setrepeatingoption(ptr, "SyncFirst", option_add_syncfirst); + } else if(strcmp(key, "Architecture") == 0) { + if(!alpm_option_get_arch()) { + setarch(ptr); + } } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) { -- 1.6.4
This implements FS#15622 Signed-off-by: Xavier Chantry <shiningxc@gmail.com> --- lib/libalpm/alpm.h | 1 + lib/libalpm/error.c | 2 ++ lib/libalpm/trans.c | 33 +++++++++++++++++++++++++++++++++ pactest/tests/upgrade080.py | 16 ++++++++++++++++ pactest/tests/upgrade081.py | 16 ++++++++++++++++ pactest/tests/upgrade082.py | 19 +++++++++++++++++++ pactest/tests/upgrade083.py | 19 +++++++++++++++++++ src/pacman/remove.c | 6 ++++++ src/pacman/sync.c | 6 ++++++ src/pacman/upgrade.c | 6 ++++++ 10 files changed, 124 insertions(+), 0 deletions(-) create mode 100644 pactest/tests/upgrade080.py create mode 100644 pactest/tests/upgrade081.py create mode 100644 pactest/tests/upgrade082.py create mode 100644 pactest/tests/upgrade083.py diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index b81b3f8..1a83f72 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -510,6 +510,7 @@ enum _pmerrno_t { PM_ERR_PKG_OPEN, PM_ERR_PKG_CANT_REMOVE, PM_ERR_PKG_INVALID_NAME, + PM_ERR_PKG_INVALID_ARCH, PM_ERR_PKG_REPO_NOT_FOUND, /* Deltas */ PM_ERR_DLT_INVALID, diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 81aaa8b..6ff1d67 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -117,6 +117,8 @@ const char SYMEXPORT *alpm_strerror(int err) return _("cannot remove all files for package"); case PM_ERR_PKG_INVALID_NAME: return _("package filename is not valid"); + case PM_ERR_PKG_INVALID_ARCH: + return _("package architecture is not valid"); case PM_ERR_PKG_REPO_NOT_FOUND: return _("no such repository"); /* Deltas */ diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 6e847e6..240bf81 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -317,6 +317,31 @@ int _alpm_trans_addtarget(pmtrans_t *trans, char *target) return(0); } +static alpm_list_t *check_arch(alpm_list_t *pkgs) +{ + alpm_list_t *i; + alpm_list_t *invalid = NULL; + + const char *arch = alpm_option_get_arch(); + if(!arch) { + return(NULL); + } + for(i = pkgs; i; i = i->next) { + pmpkg_t *pkg = i->data; + const char *pkgarch = alpm_pkg_get_arch(pkg); + if(strcmp(pkgarch,arch) && strcmp(pkgarch,"any")) { + char *string; + const char *pkgname = alpm_pkg_get_name(pkg); + const char *pkgver = alpm_pkg_get_version(pkg); + size_t len = strlen(pkgname) + strlen(pkgver) + strlen(pkgarch) + 3; + MALLOC(string, len, RET_ERR(PM_ERR_MEMORY, invalid)); + sprintf(string, "%s-%s-%s", pkgname, pkgver, pkgarch); + invalid = alpm_list_add(invalid, string); + } + } + return(invalid); +} + int _alpm_trans_prepare(pmtrans_t *trans, alpm_list_t **data) { if(data) { @@ -333,6 +358,14 @@ int _alpm_trans_prepare(pmtrans_t *trans, alpm_list_t **data) return(0); } + alpm_list_t *invalid = check_arch(trans->packages); + if(invalid) { + if(data) { + *data = invalid; + } + RET_ERR(PM_ERR_PKG_INVALID_ARCH, -1); + } + switch(trans->type) { case PM_TRANS_TYPE_UPGRADE: if(_alpm_add_prepare(trans, handle->db_local, data) == -1) { diff --git a/pactest/tests/upgrade080.py b/pactest/tests/upgrade080.py new file mode 100644 index 0000000..9ddbd70 --- /dev/null +++ b/pactest/tests/upgrade080.py @@ -0,0 +1,16 @@ +self.description = "Install a package (correct architecture)" + +p = pmpkg("dummy") +p.files = ["bin/dummy", + "usr/man/man1/dummy.1"] +p.arch = 'testarch' +self.addpkg(p) + +self.option["Architecture"] = ['testarch'] + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_EXIST=dummy") +for f in p.files: + self.addrule("FILE_EXIST=%s" % f) diff --git a/pactest/tests/upgrade081.py b/pactest/tests/upgrade081.py new file mode 100644 index 0000000..99e2231 --- /dev/null +++ b/pactest/tests/upgrade081.py @@ -0,0 +1,16 @@ +self.description = "Install a package (wrong architecture)" + +p = pmpkg("dummy") +p.files = ["bin/dummy", + "usr/man/man1/dummy.1"] +p.arch = 'testarch' +self.addpkg(p) + +self.option["Architecture"] = ['nottestarch'] + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PKG_EXIST=dummy") +for f in p.files: + self.addrule("!FILE_EXIST=%s" % f) diff --git a/pactest/tests/upgrade082.py b/pactest/tests/upgrade082.py new file mode 100644 index 0000000..0bdbdf7 --- /dev/null +++ b/pactest/tests/upgrade082.py @@ -0,0 +1,19 @@ +self.description = "Install a package (correct architecture, auto)" + +import os +machine = os.uname()[4] + +p = pmpkg("dummy") +p.files = ["bin/dummy", + "usr/man/man1/dummy.1"] +p.arch = machine +self.addpkg(p) + +self.option["Architecture"] = ['auto'] + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_EXIST=dummy") +for f in p.files: + self.addrule("FILE_EXIST=%s" % f) diff --git a/pactest/tests/upgrade083.py b/pactest/tests/upgrade083.py new file mode 100644 index 0000000..097ae02 --- /dev/null +++ b/pactest/tests/upgrade083.py @@ -0,0 +1,19 @@ +self.description = "Install a package (wrong architecture, auto)" + +import os +machine = os.uname()[4] + +p = pmpkg("dummy") +p.files = ["bin/dummy", + "usr/man/man1/dummy.1"] +p.arch = machine + 'wrong' +self.addpkg(p) + +self.option["Architecture"] = ['auto'] + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PKG_EXIST=dummy") +for f in p.files: + self.addrule("!FILE_EXIST=%s" % f) diff --git a/src/pacman/remove.c b/src/pacman/remove.c index 0efbd94..b5119fa 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -103,6 +103,12 @@ int pacman_remove(alpm_list_t *targets) pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); diff --git a/src/pacman/sync.c b/src/pacman/sync.c index dc93621..4f101f9 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -639,6 +639,12 @@ static int sync_trans(alpm_list_t *targets) alpm_strerrorlast()); switch(pm_errno) { alpm_list_t *i; + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 1570f95..e769118 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -87,6 +87,12 @@ int pacman_upgrade(alpm_list_t *targets) pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); -- 1.6.4
similarly to the $repo variable, Server can now contain $arch, which will be automatically replaced by the appropriate architecture. This allows us to have one universal mirrorlist file, for both i686 and x86_64, woohoo! TODO : doc Signed-off-by: Xavier Chantry <shiningxc@gmail.com> --- doc/pacman.conf.5.txt | 6 ++++-- etc/pacman.conf.in | 3 ++- scripts/rankmirrors.py.in | 2 ++ src/pacman/pacman.c | 17 ++++++++++++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 51c5188..bfb69b5 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -181,10 +181,12 @@ Include = /etc/pacman.d/mirrorlist During parsing, pacman will define the `$repo` variable to the name of the current section. This is often utilized in files specified using the 'Include' -directive so all repositories can use the same mirrorfile. +directive so all repositories can use the same mirrorfile. pacman also defines +the `$arch` variable to the value of `Architecture`, so the same mirrorfile can +even be used for different architectures. -------- -Server = ftp://ftp.archlinux.org/$repo/os/arch +Server = ftp://ftp.archlinux.org/$repo/os/$arch -------- The order of repositories in the configuration files matters; repositories diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 929d38b..fc841b7 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -42,6 +42,7 @@ Architecture = auto # - repositories listed first will take precedence when packages # have identical names, regardless of version number # - URLs will have $repo replaced by the name of the current repo +# - URLs will have $arch replaced by the name of the architecture # # Repository entries are of the format: # [repo-name] @@ -57,7 +58,7 @@ Architecture = auto # servers immediately after the header and they will be used before the # default mirrors. #[core] -#Server = ftp://ftp.example.com/foobar/$repo/os/i686/ +#Server = ftp://ftp.example.com/foobar/$repo/os/$arch/ # The file referenced here should contain a list of 'Server = ' lines. #Include = @sysconfdir@/pacman.d/mirrorlist diff --git a/scripts/rankmirrors.py.in b/scripts/rankmirrors.py.in index 4b253b6..6bfa661 100644 --- a/scripts/rankmirrors.py.in +++ b/scripts/rankmirrors.py.in @@ -156,6 +156,8 @@ if __name__ == "__main__": # if the $repo var is used in the url, replace it by core tempUrl = Template(serverUrl).safe_substitute(repo='core') + # if the $arch var is used in the url, replace it by i686 + tempUrl = Template(tempUrl).safe_substitute(arch='i686') # add @DBEXT@ to server name. the repo name is parsed # from the mirror url; it is the third (or fourth) dir diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 5fab247..6e5147c 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -897,7 +897,22 @@ static int _parseconfig(const char *file, const char *givensection, } } else if(strcmp(key, "Server") == 0) { /* let's attempt a replacement for the current repo */ - char *server = strreplace(ptr, "$repo", section); + char *temp = strreplace(ptr, "$repo", section); + /* let's attempt a replacement for the arch */ + const char *arch = alpm_option_get_arch(); + char *server; + if(arch) { + server = strreplace(temp, "$arch", arch); + free(temp); + } else { + if(strstr(temp, "$arch")) { + pm_printf(PM_LOG_ERROR, _("The mirror '%s' contains the $arch" + " variable, but no Architecture is defined.\n"), ptr); + ret = 1; + goto cleanup; + } + server = temp; + } if(alpm_db_setserver(db, server) != 0) { /* pm_errno is set by alpm_db_setserver */ -- 1.6.4
participants (1)
-
Xavier Chantry