--- a/doc/client_api_versions.txt Wed Apr 15 19:15:31 2015 -0700
+++ b/doc/client_api_versions.txt Mon Apr 20 17:20:36 2015 -0700
@@ -1,5 +1,12 @@
+Version 82:
+Compatible with clients using versions 72-81.
+
+ pkg.client.api.PackageInfo has changed as follows:
+ * added a new field 'last_install' to record the package last install time
+ * added a new field 'last_update' to record the package last update time
+
Version 81:
-Incompatible with clients using versions 72-80.
+Compatible with clients using versions 72-80.
pkg.client.api.ImageInterface has changed as follows:
* Introduced new non-linked image interfaces:
--- a/src/client.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/client.py Mon Apr 20 17:20:36 2015 -0700
@@ -93,7 +93,7 @@
import sys
sys.exit(1)
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
PKG_CLIENT_NAME = "pkg"
JUST_UNKNOWN = 0
--- a/src/modules/api_common.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/modules/api_common.py Mon Apr 20 17:20:36 2015 -0700
@@ -135,7 +135,7 @@
version=None, build_release=None, branch=None, packaging_date=None,
size=None, csize=None, licenses=None, links=None, hardlinks=None,
files=None, dirs=None, dependencies=None, description=None,
- attrs=None):
+ attrs=None, last_update=None, last_install=None):
self.pkg_stem = pkg_stem
self.summary = summary
@@ -159,6 +159,8 @@
self.dependencies = dependencies
self.description = description
self.attrs = attrs or {}
+ self.last_update = last_update
+ self.last_install = last_install
def __str__(self):
return str(self.fmri)
--- a/src/modules/client/api.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/modules/client/api.py Mon Apr 20 17:20:36 2015 -0700
@@ -69,6 +69,7 @@
import time
import urllib
+import pkg.catalog as catalog
import pkg.client.api_errors as apx
import pkg.client.bootenv as bootenv
import pkg.client.history as history
@@ -103,8 +104,8 @@
# things like help(pkg.client.api.PlanDescription)
from pkg.client.plandesc import PlanDescription # pylint: disable=W0611
-CURRENT_API_VERSION = 81
-COMPATIBLE_API_VERSIONS = frozenset([72, 73, 74, 75, 76, 77, 78, 79, 80,
+CURRENT_API_VERSION = 82
+COMPATIBLE_API_VERSIONS = frozenset([72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
CURRENT_API_VERSION])
CURRENT_P5I_VERSION = 1
@@ -3297,6 +3298,8 @@
img_inst_cat = self._img.get_catalog(
self._img.IMG_CATALOG_INSTALLED)
+ img_inst_base = img_inst_cat.get_part("catalog.base.C",
+ must_exist=True)
op_time = datetime.datetime.utcnow()
pubs = self.__get_temp_repo_pubs(repos)
progtrack = self.__progresstracker
@@ -3461,7 +3464,15 @@
# Only the base catalog part stores
# package state information and/or
# other metadata.
- mdata = entry["metadata"] = {}
+ mdata = {}
+ if installed:
+ mdata = dict(
+ img_inst_base.get_entry(
+ pub=pub, stem=stem,
+ ver=ver)["metadata"])
+
+ entry["metadata"] = mdata
+
states = [pkgdefs.PKG_STATE_KNOWN,
pkgdefs.PKG_STATE_ALT_SOURCE]
if cat_ver == 0:
@@ -3693,7 +3704,7 @@
def __get_pkg_list(self, pkg_list, cats=None, collect_attrs=False,
inst_cat=None, known_cat=None, patterns=misc.EmptyI,
pubs=misc.EmptyI, raise_unmatched=False, ranked=False, repos=None,
- return_fmris=False, variants=False):
+ return_fmris=False, return_metadata=False, variants=False):
"""This is the implementation of get_pkg_list. The other
function is a wrapper that uses locking. The separation was
necessary because of API functions that already perform locking
@@ -4046,7 +4057,8 @@
targets = set()
omit_var = False
- states = entry["metadata"]["states"]
+ mdata = entry["metadata"]
+ states = mdata["states"]
pkgi = pkgdefs.PKG_STATE_INSTALLED in states
ddm = lambda: collections.defaultdict(list)
attrs = collections.defaultdict(ddm)
@@ -4192,9 +4204,19 @@
if return_fmris:
pfmri = fmri.PkgFmri(name=stem, publisher=pub,
version=ver)
- yield (pfmri, summ, pcats, states, attrs)
+ if return_metadata:
+ yield (pfmri, summ, pcats, states,
+ attrs, mdata)
+ else:
+ yield (pfmri, summ, pcats, states,
+ attrs)
else:
- yield (t, summ, pcats, states, attrs)
+ if return_metadata:
+ yield (t, summ, pcats, states,
+ attrs, mdata)
+ else:
+ yield (t, summ, pcats, states,
+ attrs)
if raise_unmatched:
# Caller has requested that non-matching patterns or
@@ -4283,11 +4305,13 @@
}
try:
- for pfmri, summary, cats, states, attrs in self.__get_pkg_list(
+ for pfmri, summary, cats, states, attrs, mdata in \
+ self.__get_pkg_list(
ilist, collect_attrs=collect_attrs,
inst_cat=inst_cat, known_cat=known_cat,
patterns=fmri_strings, raise_unmatched=True,
- ranked=ranked, return_fmris=True, variants=True):
+ ranked=ranked, return_fmris=True,
+ return_metadata=True, variants=True):
release = build_release = branch = \
packaging_date = None
@@ -4383,6 +4407,8 @@
size = csize = 0
# Trim response set.
+ last_install = None
+ last_update = None
if PackageInfo.STATE in info_needed:
if unsupported is True and \
PackageInfo.UNSUPPORTED not in states:
@@ -4393,6 +4419,13 @@
states = set(states)
states.add(
PackageInfo.UNSUPPORTED)
+
+ if "last-update" in mdata:
+ last_update = catalog.basic_ts_to_datetime(
+ mdata["last-update"]).strftime("%c")
+ if "last-install" in mdata:
+ last_install = catalog.basic_ts_to_datetime(
+ mdata["last-install"]).strftime("%c")
else:
states = misc.EmptyI
@@ -4412,7 +4445,9 @@
csize=csize, pfmri=pfmri, licenses=licenses,
links=links, hardlinks=hardlinks, files=files,
dirs=dirs, dependencies=dependencies,
- description=description, attrs=attrs))
+ description=description, attrs=attrs,
+ last_update=last_update,
+ last_install=last_install))
except apx.InventoryException as e:
if e.illegal:
self.log_operation_end(
--- a/src/modules/client/client_api.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/modules/client/client_api.py Mon Apr 20 17:20:36 2015 -0700
@@ -68,7 +68,7 @@
from pkg.client.pkgdefs import *
from pkg.misc import EmptyI, msg, emsg, PipeError
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
PKG_CLIENT_NAME = "pkg"
pkg_timer = pkg.misc.Timer("pkg client")
SYSREPO_HIDDEN_URI = "<system-repository>"
@@ -2415,6 +2415,12 @@
__append_attr_lists(_("Branch"), str(pi.branch))
__append_attr_lists(_("Packaging Date"), pi.packaging_date)
+ if pi.last_install:
+ __append_attr_lists(_("Last Install Time"),
+ pi.last_install)
+ if pi.last_update:
+ __append_attr_lists(_("Last Update Time"),
+ pi.last_update)
__append_attr_lists(_("Size"), misc.bytes_to_str(pi.size))
__append_attr_lists(_("FMRI"),
pi.fmri.get_fmri(include_build=False))
--- a/src/modules/client/image.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/modules/client/image.py Mon Apr 20 17:20:36 2015 -0700
@@ -2465,6 +2465,7 @@
added = set()
removed = set()
+ updated = {}
for add_pkg, rem_pkg in pkg_pairs:
if add_pkg == rem_pkg:
continue
@@ -2472,6 +2473,10 @@
added.add(add_pkg)
if rem_pkg:
removed.add(rem_pkg)
+ if add_pkg and rem_pkg:
+ updated[add_pkg] = \
+ dict(kcat.get_entry(rem_pkg).get(
+ "metadata", {}))
combo = added.union(removed)
@@ -2485,9 +2490,25 @@
if pfmri in removed:
icat.remove_package(pfmri)
states.discard(pkgdefs.PKG_STATE_INSTALLED)
+ mdata.pop("last-install", None)
+ mdata.pop("last-update", None)
if pfmri in added:
states.add(pkgdefs.PKG_STATE_INSTALLED)
+ cur_time = pkg.catalog.now_to_basic_ts()
+ if pfmri in updated:
+ last_install = updated[pfmri].get(
+ "last-install")
+ if last_install:
+ mdata["last-install"] = \
+ last_install
+ mdata["last-update"] = \
+ cur_time
+ else:
+ mdata["last-install"] = \
+ cur_time
+ else:
+ mdata["last-install"] = cur_time
if pkgdefs.PKG_STATE_ALT_SOURCE in states:
states.discard(
pkgdefs.PKG_STATE_UPGRADABLE)
--- a/src/modules/lint/engine.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/modules/lint/engine.py Mon Apr 20 17:20:36 2015 -0700
@@ -42,7 +42,7 @@
import urllib2
PKG_CLIENT_NAME = "pkglint"
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
pkg.client.global_settings.client_name = PKG_CLIENT_NAME
class LintEngineException(Exception):
--- a/src/pkgdep.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/pkgdep.py Mon Apr 20 17:20:36 2015 -0700
@@ -43,7 +43,7 @@
import pkg.publish.dependencies as dependencies
from pkg.misc import msg, emsg, PipeError
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
PKG_CLIENT_NAME = "pkgdepend"
DEFAULT_SUFFIX = ".res"
--- a/src/sysrepo.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/sysrepo.py Mon Apr 20 17:20:36 2015 -0700
@@ -59,7 +59,7 @@
orig_cwd = None
PKG_CLIENT_NAME = "pkg.sysrepo"
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
pkg.client.global_settings.client_name = PKG_CLIENT_NAME
# exit codes
--- a/src/tests/cli/t_pkg_composite.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/tests/cli/t_pkg_composite.py Mon Apr 20 17:20:36 2015 -0700
@@ -28,7 +28,9 @@
testutils.setup_environment("../../../proto")
import pkg5unittest
+import json
import os
+import pkg.catalog as catalog
import pkg.fmri as fmri
import pkg.portable as portable
import pkg.misc as misc
@@ -364,18 +366,27 @@
# output.
self.pkg("install [email protected]")
self.pkg("info")
+
+ path = os.path.join(self.img_path(),
+ "var/pkg/state/installed/catalog.base.C")
+
+ entry = json.load(open(path))["test"]["foo"][0]
+ pkg_install = catalog.basic_ts_to_datetime(
+ entry["metadata"]["last-install"]).strftime("%c")
expected = """\
- Name: foo
- Summary: Example package foo.
- State: Installed
- Publisher: test
- Version: 1.0
- Branch: None
-Packaging Date: {pkg_date}
- Size: 41.00 B
- FMRI: {pkg_fmri}
+ Name: foo
+ Summary: Example package foo.
+ State: Installed
+ Publisher: test
+ Version: 1.0
+ Branch: None
+ Packaging Date: {pkg_date}
+Last Install Time: {pkg_install}
+ Size: 41.00 B
+ FMRI: {pkg_fmri}
""".format(pkg_date=self.foo10.version.get_timestamp().strftime("%c"),
- pkg_fmri=self.foo10.get_fmri(include_build=False))
+ pkg_fmri=self.foo10.get_fmri(include_build=False),
+ pkg_install=pkg_install)
self.assertEqualDiff(expected, self.output)
def test_02_contents(self):
--- a/src/tests/cli/t_pkg_info.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/tests/cli/t_pkg_info.py Mon Apr 20 17:20:36 2015 -0700
@@ -27,10 +27,12 @@
testutils.setup_environment("../../../proto")
import pkg5unittest
+import json
import os
import shutil
import unittest
+import pkg.catalog as catalog
import pkg.actions as actions
import pkg.fmri as fmri
@@ -745,6 +747,34 @@
self.pkg("info -r --license [email protected]")
self.assertEqual("tmp/copyright0\n", self.output)
+ def test_info_update_install(self):
+ """Test that pkg info will show last update and install time"""
+
+ os.environ["LC_ALL"] = "C"
+ self.image_create(self.rurl)
+ self.pkg("install [email protected]")
+ path = os.path.join(self.img_path(),
+ "var/pkg/state/installed/catalog.base.C")
+ entry = json.load(open(path))["test"]["bronze"][0]["metadata"]
+ last_install = catalog.basic_ts_to_datetime(
+ entry["last-install"]).strftime("%c")
+ self.pkg(("info bronze | grep 'Last Install Time: "
+ "{0}'").format(last_install))
+
+ # Now update the version.
+ self.pkg("install [email protected]")
+ entry = json.load(open(path))["test"]["bronze"][0]["metadata"]
+ last_install = catalog.basic_ts_to_datetime(
+ entry["last-install"]).strftime("%c")
+ self.pkg(("info bronze | grep 'Last Install Time: "
+ "{0}'").format(last_install))
+
+ # Last update should be existed this time.
+ last_update = catalog.basic_ts_to_datetime(
+ entry["last-update"]).strftime("%c")
+ self.pkg(("info bronze | grep 'Last Update Time: "
+ "{0}'").format(last_update))
+
class TestPkgInfoPerTestRepo(pkg5unittest.SingleDepotTestCase):
"""A separate test class is needed because these tests modify packages
--- a/src/tests/cli/t_pkg_temp_sources.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/tests/cli/t_pkg_temp_sources.py Mon Apr 20 17:20:36 2015 -0700
@@ -29,7 +29,9 @@
testutils.setup_environment("../../../proto")
import pkg5unittest
+import json
import os
+import pkg.catalog as catalog
import pkg.fmri as fmri
import pkg.portable as portable
import pkg.misc as misc
@@ -556,18 +558,27 @@
# output.
self.pkg("install -g {0} [email protected]".format(self.foo_arc))
self.pkg("info")
+
+ os.environ["LC_ALL"] = "C"
+ path = os.path.join(self.img_path(),
+ "var/pkg/state/installed/catalog.base.C")
+ entry = json.load(open(path))["test"]["foo"][0]["metadata"]
+ pkg_install = catalog.basic_ts_to_datetime(
+ entry["last-install"]).strftime("%c")
+
expected = """\
- Name: foo
- Summary: Example package foo.
- State: Installed
- Publisher: test
- Version: 1.0
- Branch: None
-Packaging Date: {pkg_date}
- Size: 41.00 B
- FMRI: {pkg_fmri}
+ Name: foo
+ Summary: Example package foo.
+ State: Installed
+ Publisher: test
+ Version: 1.0
+ Branch: None
+ Packaging Date: {pkg_date}
+Last Install Time: {pkg_install}
+ Size: 41.00 B
+ FMRI: {pkg_fmri}
""".format(pkg_date=pd(self.foo10), pkg_fmri=self.foo10.get_fmri(
- include_build=False))
+ include_build=False), pkg_install=pkg_install)
self.assertEqualDiff(expected, self.output)
# Verify that when showing package info from archive that
--- a/src/tests/pkg5unittest.py Wed Apr 15 19:15:31 2015 -0700
+++ b/src/tests/pkg5unittest.py Mon Apr 20 17:20:36 2015 -0700
@@ -136,7 +136,7 @@
# Version test suite is known to work with.
PKG_CLIENT_NAME = "pkg"
-CLIENT_API_VERSION = 81
+CLIENT_API_VERSION = 82
ELIDABLE_ERRORS = [ TestSkippedException, depotcontroller.DepotStateException ]