From 573e981f7a802ac4c49f30f382f28d2505f08a9e Mon Sep 17 00:00:00 2001
From: Nagy Gabor <ngaba@bibl.u-szeged.hu>
Date: Fri, 29 Feb 2008 13:31:37 +0100
Subject: [PATCH] New --nonew option

This is the next member of our target-list filter options (--needed, --unneeded).
With this option pacman won't add new packages (which cannot be found in localdb), only upgrade/reinstall old ones.
This implement the request of FS#8137. See also: http://www.archlinux.org/pipermail/pacman-dev/2007-October/009650.html
I also added sync022.py to test the new option.
Note: I rephrased the descriptions of --needed to emphasize that it is a filter option (--nonew is usually used with --needed).
Note: in the future we can implement a new --freshen option == --needed + --nonew.

Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu>
---
 contrib/bash_completion  |    3 ++-
 contrib/zsh_completion   |    1 +
 doc/pacman.8.txt         |   12 ++++++++++--
 lib/libalpm/alpm.h       |    3 ++-
 lib/libalpm/sync.c       |    6 ++++++
 pactest/tests/sync022.py |   20 ++++++++++++++++++++
 src/pacman/pacman.c      |    5 ++++-
 src/pacman/sync.c        |   10 ++++++++--
 8 files changed, 53 insertions(+), 7 deletions(-)
 create mode 100644 pactest/tests/sync022.py

diff --git a/contrib/bash_completion b/contrib/bash_completion
index 7f5d1b0..9d658fb 100644
--- a/contrib/bash_completion
+++ b/contrib/bash_completion
@@ -273,8 +273,9 @@ _pacman ()
           -s --search \
           -u --sysupgrade \
           -w --downloadonly \
-          -y --refresh \
+          -y --refresh \	  
           --needed \
+	  --nonew \
           --ignore \
           --ignoregroup \
           --config \
diff --git a/contrib/zsh_completion b/contrib/zsh_completion
index e5ad92b..5718abc 100644
--- a/contrib/zsh_completion
+++ b/contrib/zsh_completion
@@ -92,6 +92,7 @@ _pacman_opts_sync_modifiers=(
 		_pacman_completions_all_groups'
 	'--asdeps[Install packages as non-explicitly installed]'
 	'--asexplicit[Install packages as explicitly installed]'
+	'--nonew[skip not installed packages]'
 )
 
 # handles --action subcommand
diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index 8a3f675..0e668bb 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -298,8 +298,16 @@ Sync Options[[SO]]
 	to date.
 
 *\--needed*::
-	Only install the targets that are not already installed and up-to-date.
-
+	Pacman won't reinstall packages, ie. it won't "upgrade" already
+	up-to-date packages. This is mostly useful in group operations.
+
+*\--nonew*::
+	Pacman won't install new (not-yet-installed) packages, except if they are
+	needed by others (as dependency). This is mostly used in group
+	operations to restrict pacman to installed packages of the group.
+	For example 'pacman -S base --nonew --needed' will upgrade your
+	base group, but won't add new packages from base.
+	
 *\--ignore* <'package'>::
 	Directs pacman to ignore upgrades of package even if there is one
 	available. Multiple packages can be specified by separating them
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index d605004..2de3a8e 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -280,7 +280,8 @@ typedef enum _pmtransflag_t {
 	PM_TRANS_FLAG_PRINTURIS = 0x1000,
 	PM_TRANS_FLAG_NEEDED = 0x2000,
 	PM_TRANS_FLAG_ALLEXPLICIT = 0x4000,
-	PM_TRANS_FLAG_UNNEEDED = 0x8000
+	PM_TRANS_FLAG_UNNEEDED = 0x8000,
+	PM_TRANS_FLAG_NONEW = 0x10000
 } pmtransflag_t;
 
 /* Transaction Events */
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 8d3e04c..aed9b8c 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -340,6 +340,12 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy
 				}
 			}
 		}
+	} else {
+		if(trans->flags & PM_TRANS_FLAG_NONEW) {
+			_alpm_log(PM_LOG_DEBUG, _("%s is not installed, nonew was set -- skipping\n"),
+					alpm_pkg_get_name(spkg));
+			return(0);
+		}
 	}
 
 	/* add the package to the transaction */
diff --git a/pactest/tests/sync022.py b/pactest/tests/sync022.py
new file mode 100644
index 0000000..6d1019a
--- /dev/null
+++ b/pactest/tests/sync022.py
@@ -0,0 +1,20 @@
+self.description = "Upgrade group (--nonew)"
+
+sp1 = pmpkg("pkg1", "2.0-1")
+sp1.groups = ["grp"]
+self.addpkg2db("sync", sp1);
+
+sp2 = pmpkg("pkg2")
+sp2.groups = ["grp"]
+self.addpkg2db("sync", sp2);
+
+lp = pmpkg("pkg1", "1.0-1")
+lp.groups = ["grp"]
+self.addpkg2db("local", lp);
+
+self.args = "-S grp --nonew"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_EXIST=pkg1")
+self.addrule("!PKG_EXIST=pkg2")
+self.addrule("PKG_VERSION=pkg1|2.0-1")
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index f185320..d7bbf81 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -131,7 +131,8 @@ static void usage(int op, const char * const myname)
 			printf(_("  -u, --sysupgrade     upgrade all packages that are out of date\n"));
 			printf(_("  -w, --downloadonly   download packages but do not install/upgrade anything\n"));
 			printf(_("  -y, --refresh        download fresh package databases from the server\n"));
-			printf(_("      --needed         only upgrade outdated or not yet installed packages\n"));
+			printf(_("      --nonew          skip not installed packages (but pull all needed deps)\n"));
+			printf(_("      --needed         do not reinstall up-to-date packages\n"));
 			printf(_("      --ignore <pkg>   ignore a package upgrade (can be used more than once)\n"));
 			printf(_("      --ignoregroup <grp>\n"
 			         "                       ignore a group upgrade (can be used more than once)\n"));
@@ -351,6 +352,7 @@ static int parseargs(int argc, char *argv[])
 		{"ignoregroup", required_argument, 0, 1010},
 		{"needed",     no_argument,       0, 1011},
 		{"asexplicit",     no_argument,   0, 1012},
+		{"nonew",     no_argument,       0, 1013},
 		{0, 0, 0, 0}
 	};
 
@@ -425,6 +427,7 @@ static int parseargs(int argc, char *argv[])
 			case 1012:
 				config->flags |= PM_TRANS_FLAG_ALLEXPLICIT;
 				break;
+			case 1013: config->flags |= PM_TRANS_FLAG_NONEW; break;
 			case 'A': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_ADD); 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;
diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index 2dbf3f2..8706078 100644
--- a/src/pacman/sync.c
+++ b/src/pacman/sync.c
@@ -590,14 +590,20 @@ static int sync_trans(alpm_list_t *targets)
 					grp = alpm_db_readgrp(db, targ);
 					if(grp) {
 						alpm_list_t *k;
+						int whole_content;
 
 						found++;
 						printf(_(":: group %s (including ignored packages):\n"), targ);
 						/* remove dupe entries in case a package exists in multiple repos */
 						const alpm_list_t *grppkgs = alpm_grp_get_pkgs(grp);
 						alpm_list_t *pkgs = alpm_list_remove_dupes(grppkgs);
-						list_display("   ", pkgs);
-						if(yesno(1, _(":: Install whole content?"))) {
+						if(config->flags & PM_TRANS_FLAG_NONEW) {
+							whole_content = 1;
+						} else {
+							list_display("   ", pkgs);
+							whole_content = yesno(1, _(":: Install whole content?"));
+						}
+						if(whole_content) {
 							for(k = pkgs; k; k = alpm_list_next(k)) {
 								targets = alpm_list_add(targets, strdup(alpm_list_getdata(k)));
 							}
-- 
1.5.2.5

