summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2021-04-23 11:37:28 +0200
committerJulian Andres Klode <julian.klode@canonical.com>2021-04-23 12:26:46 +0200
commit80dd1447595c536d31912c486ac5e96f983ccc7a (patch)
tree1253ecca8e3d9c609ce0a09417f2a1b900358f2a
parentdc11a4422d99cb49817c827b9f827617b5880600 (diff)
json: Hook protocol 0.2 (added upgrade,downgrade,reinstall modes)
Hook protocol 0.2 makes the new fields we added mandatory, and replaces `install` mode with `upgrade`, `downgrade`, `reinstall` where appropriate. Hook negotiation is hacky, but it's the best we can do for now. Users are advised to upgrade to 0.2
-rw-r--r--apt-private/private-json-hooks.cc49
-rw-r--r--doc/json-hooks-protocol.md48
-rwxr-xr-xtest/integration/test-apt-cli-json-hooks88
3 files changed, 144 insertions, 41 deletions
diff --git a/apt-private/private-json-hooks.cc b/apt-private/private-json-hooks.cc
index a40597e0a..957140525 100644
--- a/apt-private/private-json-hooks.cc
+++ b/apt-private/private-json-hooks.cc
@@ -17,6 +17,7 @@
#include <ostream>
#include <sstream>
#include <stack>
+#include <unordered_map>
#include <signal.h>
#include <sys/socket.h>
@@ -265,7 +266,7 @@ static void DpkgChrootDirectory()
/**
* @brief Send a notification to the hook's stream
*/
-static void NotifyHook(std::ostream &os, std::string const &method, const char **FileList, CacheFile &Cache, std::set<std::string> const &UnknownPackages)
+static void NotifyHook(std::ostream &os, std::string const &method, const char **FileList, CacheFile &Cache, std::set<std::string> const &UnknownPackages, int hookVersion)
{
SortedPackageUniverse Universe(Cache);
JsonWriter jsonWriter{os};
@@ -311,7 +312,14 @@ static void NotifyHook(std::ostream &os, std::string const &method, const char *
switch (Cache[Pkg].Mode)
{
case pkgDepCache::ModeInstall:
- jsonWriter.name("mode").value("install");
+ if (Pkg->CurrentVer != 0 && Cache[Pkg].Upgrade() && hookVersion >= 0x020)
+ jsonWriter.name("mode").value("upgrade");
+ else if (Pkg->CurrentVer != 0 && Cache[Pkg].Downgrade() && hookVersion >= 0x020)
+ jsonWriter.name("mode").value("downgrade");
+ else if (Pkg->CurrentVer != 0 && Cache[Pkg].ReInstall() && hookVersion >= 0x020)
+ jsonWriter.name("mode").value("reinstall");
+ else
+ jsonWriter.name("mode").value("install");
break;
case pkgDepCache::ModeDelete:
jsonWriter.name("mode").value(Cache[Pkg].Purge() ? "purge" : "deinstall");
@@ -344,7 +352,7 @@ static void NotifyHook(std::ostream &os, std::string const &method, const char *
static std::string BuildHelloMessage()
{
std::stringstream Hello;
- JsonWriter(Hello).beginObject().name("jsonrpc").value("2.0").name("method").value("org.debian.apt.hooks.hello").name("id").value(0).name("params").beginObject().name("versions").beginArray().value("0.1").endArray().endObject().endObject();
+ JsonWriter(Hello).beginObject().name("jsonrpc").value("2.0").name("method").value("org.debian.apt.hooks.hello").name("id").value(0).name("params").beginObject().name("versions").beginArray().value("0.1").value("0.2").endArray().endObject().endObject();
return Hello.str();
}
@@ -361,11 +369,10 @@ static std::string BuildByeMessage()
/// @brief Run the Json hook processes in the given option.
bool RunJsonHook(std::string const &option, std::string const &method, const char **FileList, CacheFile &Cache, std::set<std::string> const &UnknownPackages)
{
- std::stringstream ss;
- NotifyHook(ss, method, FileList, Cache, UnknownPackages);
- std::string TheData = ss.str();
+ std::unordered_map<int, std::string> notifications;
std::string HelloData = BuildHelloMessage();
std::string ByeData = BuildByeMessage();
+ int hookVersion;
bool result = true;
@@ -465,6 +472,20 @@ bool RunJsonHook(std::string const &option, std::string const &method, const cha
goto out;
}
+ if (strstr(line, "\"0.1\""))
+ {
+ hookVersion = 0x010;
+ }
+ else if (strstr(line, "\"0.2\""))
+ {
+ hookVersion = 0x020;
+ }
+ else
+ {
+ _error->Error("Unknown hook version in handshake from hook %s: %s", Opts->Value.c_str(), line);
+ goto out;
+ }
+
size = getline(&line, &linesize, F);
if (size < 0)
{
@@ -476,9 +497,18 @@ bool RunJsonHook(std::string const &option, std::string const &method, const cha
_error->Error("Expected empty line after handshake from %s, received %s", Opts->Value.c_str(), line);
goto out;
}
-
- fwrite(TheData.data(), TheData.size(), 1, F);
- fwrite("\n\n", 2, 1, F);
+ {
+ std::string &data = notifications[hookVersion];
+ if (data.empty())
+ {
+ std::stringstream ss;
+ NotifyHook(ss, method, FileList, Cache, UnknownPackages, hookVersion);
+ ;
+ data = ss.str();
+ }
+ fwrite(data.data(), data.size(), 1, F);
+ fwrite("\n\n", 2, 1, F);
+ }
fwrite(ByeData.data(), ByeData.size(), 1, F);
fwrite("\n\n", 2, 1, F);
@@ -490,6 +520,7 @@ bool RunJsonHook(std::string const &option, std::string const &method, const cha
result = _error->Error("Failure running hook %s", Opts->Value.c_str());
break;
}
+
}
signal(SIGINT, old_sigint);
signal(SIGPIPE, old_sigpipe);
diff --git a/doc/json-hooks-protocol.md b/doc/json-hooks-protocol.md
index 3c7f6e4f2..4c0429d06 100644
--- a/doc/json-hooks-protocol.md
+++ b/doc/json-hooks-protocol.md
@@ -1,3 +1,5 @@
+Version: 0.2
+
## JSON Hooks
APT 1.6 introduces support for hooks that talk JSON-RPC 2.0. Hooks act
@@ -59,7 +61,7 @@ The following methods are supported:
1. `org.debian.apt.hooks.install.pre-prompt` - Run before the package list and y/n prompt
1. `org.debian.apt.hooks.install.package-list` - (optional in 0.1) Run after the package list. You could display additional lists of packages here
-1. `org.debian.apt.hooks.install.statistics` - (optional in 0.1) Run after the package list. You could display additional lists of packages here
+1. `org.debian.apt.hooks.install.statistics` - (optional in 0.1) Run after the count of packages to upgrade/install. You could display additional information here, such as `5 security upgrades`
1. `org.debian.apt.hooks.install.post` - Run after success
1. `org.debian.apt.hooks.install.fail` - Run after failed install
1. `org.debian.apt.hooks.search.pre` - Run before search
@@ -90,29 +92,30 @@ install. Each package has the following attributes:
- *id*: An unsigned integer describing the package
- *name*: The name of the package
- *architecture*: The architecture of the package. For `"all"` packages, this will be the native architecture;
- use per-version architecture fields to see `"all"`.
+ use per-version architecture fields to see `"all"`.
-- *mode*: One of `install`, `deinstall`, `purge`, or `keep`. `keep`
- is not exposed in 0.1. To determine an upgrade, check
- that a current version is installed.
+- *mode*: One of `install`, `upgrade`, `downgrade`, `reinstall`, `deinstall`, `purge`, `keep`.
+ Version 0.1 does not implement `upgrade`, `downgrade`, and `reinstall` - all of them are represented
+ as `install`, and you have to compare the `current` version to the `install` version to figure out if
+ is one of those.
- One of the following optional fields may be set to true to indicate a change relative to an installed version:
- - *downgrade*: true if downgrading
- - *upgrade*: true if upgrading
- - *reinstall*: true if reinstall flag is set
+- *downgrade*: true if downgrading
+- *upgrade*: true if upgrading
+- *reinstall*: true if reinstall flag is set
- *automatic*: Whether the package is/will be automatically installed
- *versions*: An array with up to 3 fields:
- - *candidate*: The candidate version
- - *install*: The version to be installed
- - *current*: The version currently installed
+- *candidate*: The candidate version
+- *install*: The version to be installed
+- *current*: The version currently installed
- Each version is represented as an object with the following fields:
+Each version is represented as an object with the following fields:
- - *id*: An unsigned integer
- - *version*: The version as a string
- - *architecture*: Architecture of the version
- - *pin*: The pin priority (optional)
- - *origins*: Sources from which the package is retrieved (optional, not in older versions)
+- *id*: An unsigned integer
+- *version*: The version as a string
+- *architecture*: Architecture of the version
+- *pin*: The pin priority (optional)
+- *origins*: Sources from which the package is retrieved (since 0.2)
Each origin is represented as an object with the following fields:
@@ -173,3 +176,14 @@ protocol version only (for example, 1.7 may only support 0.2).
Additional fields may be added to objects without bumping the protocol
version.
+
+# Changes:
+
+## Version 0.2
+
+The 0.2 protocol makes one incompatible change, and adds several new compatible changes, all of which are optional in 0.1,
+but mandatory in 0.2.
+
+* (incompatible change) The `mode` flag of arguments gained `upgrade`, `downgrade`, `reinstall` modes. All of these are `install`
+* (compatible change) The hooks `org.debian.apt.hooks.install.package-list` and `org.debian.apt.hooks.install.statistics` have been added
+* (compatible change) Version objects gained a new `origins` array
diff --git a/test/integration/test-apt-cli-json-hooks b/test/integration/test-apt-cli-json-hooks
index 0e6745d00..59cf6e5ef 100755
--- a/test/integration/test-apt-cli-json-hooks
+++ b/test/integration/test-apt-cli-json-hooks
@@ -24,6 +24,7 @@ insertinstalledpackage 'upgrade' 'i386' '1.0'
setupaptarchive
APTARCHIVE="$(readlink -f ./aptarchive)"
+export TEST_HOOK_VERSION=0.2
cat >> json-hook.sh << EOF
#!/bin/bash
@@ -34,7 +35,7 @@ while true; do
if echo "\$request" | grep -q ".hello"; then
echo "HOOK: HELLO"
- printf '{"jsonrpc": "2.0", "result": {"version": "0.1"}, "id": 0}\n\n' >&\$APT_HOOK_SOCKET
+ printf '{"jsonrpc": "2.0", "result": {"version": "'\$TEST_HOOK_VERSION'"}, "id": 0}\n\n' >&\$APT_HOOK_SOCKET
fi
if echo "\$request" | grep -q ".bye"; then
@@ -61,7 +62,7 @@ EOF
############################# Success search #######################
testsuccessequal 'HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.pre","params":{"command":"search","search-terms":["foo"],"unknown-packages":[],"packages":[]}}
HOOK: empty
@@ -72,7 +73,7 @@ foo/unstable 1.0 all
Some description that has a unusual word xxyyzz and aabbcc and a UPPERCASE
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.post","params":{"command":"search","search-terms":["foo"],"unknown-packages":[],"packages":[]}}
HOOK: empty
@@ -80,7 +81,7 @@ HOOK: BYE' apt search foo
############################# Failed search #######################
testsuccessequal 'HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.pre","params":{"command":"search","search-terms":["foox"],"unknown-packages":[],"packages":[]}}
HOOK: empty
@@ -88,7 +89,7 @@ HOOK: BYE
Sorting...
Full Text Search...
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.search.fail","params":{"command":"search","search-terms":["foox"],"unknown-packages":[],"packages":[]}}
HOOK: empty
@@ -100,7 +101,7 @@ HOOK: BYE' apt search foox
testfailureequal 'Reading package lists...
Building dependency tree...
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.fail","params":{"command":"install","search-terms":["foxxx"],"unknown-packages":["foxxx"],"packages":[]}}
HOOK: empty
@@ -112,7 +113,7 @@ E: Unable to locate package foxxx' apt install foxxx
testsuccessequal 'Reading package lists...
Building dependency tree...
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}}
HOOK: empty
@@ -120,14 +121,14 @@ HOOK: BYE
The following NEW packages will be installed:
foo
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}}
HOOK: empty
HOOK: BYE
0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}}
HOOK: empty
@@ -135,7 +136,7 @@ HOOK: BYE
Inst foo (1.0 Lemons:unstable [all])
Conf foo (1.0 Lemons:unstable [all])
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"install","search-terms":["foo"],"unknown-packages":[],"packages":[{"id":2,"name":"foo","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":2,"version":"1.0","architecture":"all","pin":500,"origins":[{"archive":"unstable","codename":"sid","origin":"Oranges","label":"Lemons","site":""}]}}}]}}
HOOK: empty
@@ -146,7 +147,7 @@ HOOK: BYE' apt install foo -s
testfailureequal 'Reading package lists...
Building dependency tree...
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.fail","params":{"command":"dist-upgrade","search-terms":["foxxx"],"unknown-packages":["foxxx"],"packages":[]}}
HOOK: empty
@@ -159,7 +160,44 @@ testsuccessequal 'Reading package lists...
Building dependency tree...
Calculating upgrade...
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
+HOOK: empty
+HOOK: BYE
+The following packages will be upgraded:
+ upgrade
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
+HOOK: empty
+HOOK: BYE
+1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
+HOOK: empty
+HOOK: BYE
+Inst upgrade [1.0] (2.0 Lemons:testing [i386])
+Conf upgrade (2.0 Lemons:testing [i386])
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"upgrade","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
+HOOK: empty
+HOOK: BYE' apt dist-upgrade -s
+
+
+################## version 0.1 #########################
+TEST_HOOK_VERSION=0.1
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+Calculating upgrade...
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.pre-prompt","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
HOOK: empty
@@ -167,14 +205,14 @@ HOOK: BYE
The following packages will be upgraded:
upgrade
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.package-list","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
HOOK: empty
HOOK: BYE
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.statistics","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
HOOK: empty
@@ -182,11 +220,31 @@ HOOK: BYE
Inst upgrade [1.0] (2.0 Lemons:testing [i386])
Conf upgrade (2.0 Lemons:testing [i386])
HOOK: HELLO
-HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1"]}}
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
HOOK: empty
HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.install.post","params":{"command":"dist-upgrade","search-terms":[],"unknown-packages":[],"packages":[{"id":1,"name":"upgrade","architecture":"i386","mode":"install","automatic":false,"versions":{"candidate":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"install":{"id":1,"version":"2.0","architecture":"i386","pin":500,"origins":[{"archive":"testing","codename":"testing","origin":"Oranges","label":"Lemons","site":""}]},"current":{"id":4,"version":"1.0","architecture":"i386","pin":100,"origins":[]}}}]}}
HOOK: empty
HOOK: BYE' apt dist-upgrade -s
+
+
+################## Wrong version #########################
+TEST_HOOK_VERSION=42
+
+testfailureequal 'Reading package lists...
+Building dependency tree...
+Calculating upgrade...
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+HOOK: HELLO
+HOOK: request {"jsonrpc":"2.0","method":"org.debian.apt.hooks.hello","id":0,"params":{"versions":["0.1","0.2"]}}
+HOOK: empty
+E: Unknown hook version in handshake from hook '$HOOK': {"jsonrpc": "2.0", "result": {"version": "42"}, "id": 0}
+E: Sub-process '$HOOK' returned an error code (1)
+E: Failure running hook '$HOOK'
+E: Unknown hook version in handshake from hook '$HOOK': {"jsonrpc": "2.0", "result": {"version": "42"}, "id": 0}
+E: Sub-process '$HOOK' returned an error code (1)
+E: Failure running hook '$HOOK'' apt dist-upgrade -s
################## Error in hello response #########################
cat > json-hook.sh << EOF