summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Kreuzer <andreas.kreuzer@open-infrastructure.net>2017-05-08 15:57:21 +0000
committerAndreas Kreuzer <andreas.kreuzer@open-infrastructure.net>2017-05-18 11:53:41 +0000
commit9478feaa22861c54187e1254ace083c67798d7c2 (patch)
treee9a7d38aa24417ca4f04be1546749a27746770d1
parentAdding Makefile. (diff)
downloadpackage-tracker-9478feaa22861c54187e1254ace083c67798d7c2.tar.xz
package-tracker-9478feaa22861c54187e1254ace083c67798d7c2.zip
Adding bin/package-tracker.
Signed-off-by: Andreas Kreuzer <andreas.kreuzer@open-infrastructure.net>
-rwxr-xr-xbin/package-tracker801
1 files changed, 801 insertions, 0 deletions
diff --git a/bin/package-tracker b/bin/package-tracker
new file mode 100755
index 0000000..6fa4b5a
--- /dev/null
+++ b/bin/package-tracker
@@ -0,0 +1,801 @@
+#!/usr/bin/env python3
+
+# package-tracker - Compare and track package versions in debian repositories
+# Copyright (C) 2017 Andreas Kreuzer <andreas.kreuzer@open-infrastructure.net>
+#
+# 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 3 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/>.
+
+import sys
+import os
+import os.path
+import argparse
+import apt
+import apt_pkg
+import re
+import logging
+import time
+
+software = u"package-tracker"
+program = sys.argv[0]
+install_path = "/"
+apt_root_path = "var/lib/" + software
+config_path = "etc/" + software
+log_file = "var/log/" + software + "/" + software + ".log"
+template_path = "usr/share/" + software + "/templates"
+
+# --------------------------------
+# Argument handling with argparse
+#
+def check_args_source(check_arg):
+ """
+ Check validity of sources file arguments.
+
+ This is the handler for argparse to verfiy the argument passed to the
+ program.
+
+ Parameters
+ ----------
+ check_arg : string
+ Given argument from comand line
+
+ Returns
+ -------
+ string
+ Full path to file or given argument if invalid
+
+ """
+
+ file_path = os.path.join(config_path, check_arg)
+ if (os.path.exists(os.path.join(install_path, file_path))):
+ return file_path
+ else:
+ msg = file_path + " does not exist"
+ raise argparse.ArgumentTypeError(msg)
+
+ return check_arg
+
+parser = argparse.ArgumentParser(
+ description="Compare and track package versions in debian repositories"
+)
+parser.add_argument(
+ "READ",
+ help="apt sources file to read",
+ type=check_args_source
+)
+parser.add_argument(
+ "COMPARE",
+ help="apt sources file to compare against",
+ type=check_args_source
+)
+parser.add_argument(
+ "-t", "--filter-type",
+ help="displays only given action (default: %(default)s)",
+ choices=["all", "lower", "obsolete", "ok"],
+ default="all"
+)
+parser.add_argument(
+ "-o", "--output-type",
+ help="output format type (default: %(default)s)",
+ choices=["stdout", "html"],
+ default="stdout"
+)
+parser.add_argument(
+ "-f", "--file-path",
+ help="file path to output report",
+ default="report.html"
+)
+parser.add_argument(
+ "-i", "--ignore-tag",
+ help="remove given tag from the end of version string"
+)
+parser.add_argument(
+ "-v", "--verbose",
+ help="print summary informations",
+ action="store_true"
+)
+parser.add_argument(
+ "-d", "--debug",
+ help="log debug information",
+ action="store_true"
+)
+args = parser.parse_args()
+
+
+# --------------------------------
+# Function definitions
+#
+def exit_critical(message):
+ logging.error(message)
+ print("Exiting: ", message)
+ sys.exit(1)
+
+def bit_isset(number, mask):
+ """ Testing a number against a binary mask """
+ return ((number & mask) == mask)
+
+def relink_sources_file(filename):
+ """
+ Creates a symlink of the desired file to sources.list
+
+ Parameters
+ ----------
+ filename : string
+ relative path to sources file
+ """
+ global apt_root_path, config_path, install_path
+
+ symlink_dir = os.path.join(
+ install_path,
+ apt_root_path,
+ "etc/apt/sources.list"
+ )
+
+ if (os.path.exists(symlink_dir)):
+ os.remove(symlink_dir)
+
+ os.symlink(
+ os.path.join(install_path, filename),
+ symlink_dir
+ )
+
+PT_VERSION_COMPARE_ERROR = 0
+PT_VERSION_EQUAL = 1
+PT_VERSION_LOWER = 2
+PT_VERSION_HIGHER = 4
+PT_VERSION_IGNORED_TAG = 8
+PT_VERSION_TAG_NORMAL = 16
+PT_VERSION_TAG_LOWER = 32
+PT_VERSION_TAG_HIGHER = 64
+PT_VERSION_OBSOLETE = 128
+PT_VERSION_BINNMU = 256
+
+def compare_debug(compare_result):
+ """ Create a human readable output of the compare result """
+ global PT_VERSION_COMPARE_ERROR, PT_VERSION_EQUAL, PT_VERSION_LOWER
+ global PT_VERSION_HIGHER, PT_VERSION_IGNORED_TAG
+ global PT_VERSION_TAG_NORMAL, PT_VERSION_TAG_LOWER
+ global PT_VERSION_TAG_HIGHER
+
+ log_string = "Compare result:"
+ if(compare_result == PT_VERSION_COMPARE_ERROR):
+ logging.debug(log_string + "PT_VERSION_COMPARE_ERROR");
+ return
+ if((compare_result & PT_VERSION_EQUAL)
+ == PT_VERSION_EQUAL):
+ log_string += " PT_VERSION_EQUAL"
+ if((compare_result & PT_VERSION_LOWER)
+ == PT_VERSION_LOWER):
+ log_string += " PT_VERSION_LOWER"
+ if((compare_result & PT_VERSION_HIGHER)
+ == PT_VERSION_HIGHER):
+ log_string += " PT_VERSION_HIGHER"
+ if((compare_result & PT_VERSION_IGNORED_TAG)
+ == PT_VERSION_IGNORED_TAG):
+ log_string += " PT_VERSION_IGNORED_TAG"
+ if((compare_result & PT_VERSION_TAG_NORMAL)
+ == PT_VERSION_TAG_NORMAL):
+ log_string += " PT_VERSION_TAG_NORMAL"
+ if((compare_result & PT_VERSION_TAG_LOWER)
+ == PT_VERSION_TAG_LOWER):
+ log_string += " PT_VERSION_TAG_LOWER"
+ if((compare_result & PT_VERSION_TAG_HIGHER)
+ == PT_VERSION_TAG_HIGHER):
+ log_string += " PT_VERSION_TAG_HIGHER"
+ if((compare_result & PT_VERSION_OBSOLETE)
+ == PT_VERSION_OBSOLETE):
+ log_string += " PT_VERSION_OBSOLETE"
+ if((compare_result & PT_VERSION_BINNMU)
+ == PT_VERSION_BINNMU):
+ log_string += " PT_VERSION_BINNMU"
+
+ logging.debug(log_string)
+
+update_counter = 0
+equal_counter = 0
+obsolete_counter = 0
+def compare_versions(from_version, to_version):
+ """
+ Compares two given versions with apt_pkg module
+
+ Parameters
+ ----------
+ from_version : string
+ Version string to compare from
+ to_version : string
+ Version string to compare against
+
+ Returns
+ -------
+ A binary representation of the compare result. Used to match against binary
+ masks.
+ """
+ global update_counter, equal_counter
+ compare_result = 0
+
+ if (args.ignore_tag != None):
+ version_re = re.search(
+ r'(?P<debrev>-[0-9]+)?(?P<tag>(?P<tagmod>[~+]?)' + args.ignore_tag + r'(?P<tagrev>[0-9]+))$',
+ from_version
+ )
+ if (version_re):
+ # We have found a tag from a debian derrivative
+ compare_result |= PT_VERSION_IGNORED_TAG
+
+ if (version_re.group('tagmod') == '~'):
+ compare_result |= PT_VERSION_TAG_LOWER
+ elif (version_re.group('tagmod') == '+'):
+ compare_result |= PT_VERSION_TAG_HIGHER
+ else:
+ compare_result |= PT_VERSION_TAG_NORMAL
+
+ # Trim the version string
+ trimpos = version_re.start('tagmod')
+ if ((version_re.group('debrev') == '-0')
+ and bit_isset(compare_result, PT_VERSION_TAG_HIGHER)):
+ trimpos = version_re.start(0)
+ version = from_version[:trimpos]
+ else:
+ version = from_version
+
+ # Search for a binNMU package version
+ if(re.search(r'\+b[0-9]+$', to_version)):
+ compare_result |= PT_VERSION_BINNMU
+
+ result = apt_pkg.version_compare(version, to_version)
+ if (result > 0):
+ compare_result |= PT_VERSION_HIGHER
+ equal_counter += 1
+ elif (result < 0):
+ compare_result |= PT_VERSION_LOWER
+ update_counter += 1
+ else:
+ compare_result |= PT_VERSION_EQUAL
+ equal_counter += 1
+
+ return compare_result
+
+def print_package_message(package, compare_result):
+ """
+ Print information for each version differences
+
+ Parameters
+ ----------
+ package : string
+ Package name (without architecture)
+ compare_result : binary
+ Result of compared versions from compare_versions()
+ """
+ global query_cache
+ global compare_cache
+ global args
+
+ tmp = None
+
+ if ((args.filter_type == "lower") or (args.filter_type == "all")
+ and bit_isset(compare_result, PT_VERSION_LOWER)):
+ tmp = package + " is lower in version"
+ if (bit_isset(compare_result, PT_VERSION_BINNMU)):
+ tmp += " [NMU]"
+ tmp += "\n"
+
+ elif ((args.filter_type == "ok" or args.filter_type == "all")
+ and (bit_isset(compare_result, PT_VERSION_EQUAL)
+ or bit_isset(compare_result, PT_VERSION_HIGHER))
+ ):
+ tmp = package + "\n"
+
+ elif ((args.filter_type == "obsolete") or (args.filter_type == "all")
+ and bit_isset(compare_result, PT_VERSION_OBSOLETE)):
+ tmp = package + " is obsolete\n"
+
+ if (tmp):
+ tmp += "\tparent version: " + compare_cache[package].versions[0].source_version + "\n"
+ tmp += "\tcurrent version: " + query_cache[package].versions[0].source_version
+ print()
+ print(tmp)
+
+
+# --------------------------------
+# Templated output
+#
+template_rawdata = ''
+template_data = {}
+template_data['main'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+template_data['security'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+template_data['updates'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+template_data['extras'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+template_data['backports'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+template_data['backports-extras'] = { 'rawspan': '', 'rawelement': '', 'elements': '', 'counter': 0 }
+
+def load_template():
+ """ Initiates templated output and loads the template """
+ global args
+ global install_path, template_path
+ global template_rawdata, template_data
+
+ #FIXME: using command parameter to switch to another template
+ file_path = os.path.join(install_path, template_path)
+ file_name = ''
+ if (args.output_type == "html"):
+ file_name = "report.html.in"
+ f = open(file_path + "/" + file_name, 'r')
+ if (not f):
+ exit_critical("Cannot read html template: ", file_path + "/" + file_name)
+ template_rawdata = f.read()
+ f.close()
+
+ m = re.search(r'{%PT_CONTENT_SPAN_MAIN%}(.+?){%/PT_CONTENT_SPAN_MAIN%}',
+ template_rawdata, re.DOTALL)
+ #FIXME: checks for other template content place holder below
+ if (not m):
+ exit_critical("Template error: PT_CONTENT_SPAN_MAIN not found.")
+ template_data['main']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_MAIN%}(.+?){%/PT_CONTENT_ELEMENTS_MAIN%}',
+ template_rawdata, re.DOTALL)
+ template_data['main']['rawelement'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_SPAN_SECURITY%}(.+?){%/PT_CONTENT_SPAN_SECURITY%}',
+ template_rawdata, re.DOTALL)
+ template_data['security']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_SECURITY%}(.+?){%/PT_CONTENT_ELEMENTS_SECURITY%}',
+ template_rawdata, re.DOTALL)
+ template_data['security']['rawelement'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_SPAN_UPDATES%}(.+?){%/PT_CONTENT_SPAN_UPDATES%}',
+ template_rawdata, re.DOTALL)
+ template_data['updates']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_UPDATES%}(.+?){%/PT_CONTENT_ELEMENTS_UPDATES%}',
+ template_rawdata, re.DOTALL)
+ template_data['updates']['rawelement'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_SPAN_EXTRAS%}(.+?){%/PT_CONTENT_SPAN_EXTRAS%}',
+ template_rawdata, re.DOTALL)
+ template_data['extras']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_EXTRAS%}(.+?){%/PT_CONTENT_ELEMENTS_EXTRAS%}',
+ template_rawdata, re.DOTALL)
+ template_data['extras']['rawelement'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_SPAN_BACKPORTS%}(.+?){%/PT_CONTENT_SPAN_BACKPORTS%}',
+ template_rawdata, re.DOTALL)
+ template_data['backports']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_BACKPORTS%}(.+?){%/PT_CONTENT_ELEMENTS_BACKPORTS%}',
+ template_rawdata, re.DOTALL)
+ template_data['backports']['rawelement'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_SPAN_BACKPORTSEXTRAS%}(.+?){%/PT_CONTENT_SPAN_BACKPORTSEXTRAS%}',
+ template_rawdata, re.DOTALL)
+ template_data['backports-extras']['rawspan'] = m.group(1)
+
+ m = re.search(r'{%PT_CONTENT_ELEMENTS_BACKPORTSEXTRAS%}(.+?){%/PT_CONTENT_ELEMENTS_BACKPORTSEXTRAS%}',
+ template_rawdata, re.DOTALL)
+ template_data['backports-extras']['rawelement'] = m.group(1)
+
+#FIXME: Parameters for all attributes to output into the table. As such
+# lookup via cache will not be nessary and templating engine can
+# be moved to a module.
+def add_template_element(suite, package, compare_result):
+ """
+ Build result data for template engine
+
+ Parameters
+ ----------
+ suite : string
+ Archive suite name
+ package : string
+ Package name (without architecture)
+ compare_result : binary
+ Result of compared versions from compare_versions()
+ """
+ global template_data
+
+ action = ""
+ if ((bit_isset(compare_result, PT_VERSION_EQUAL)
+ or bit_isset(compare_result, PT_VERSION_HIGHER))
+ and (args.filter_type == "ok" or args.filter_type == "all")):
+ action = "ok"
+ elif (bit_isset(compare_result, PT_VERSION_LOWER)
+ and (args.filter_type == "lower" or args.filter_type == "all")):
+ action = "lower"
+ if (bit_isset(compare_result, PT_VERSION_BINNMU)):
+ action += " [NMU]"
+ elif (bit_isset(compare_result, PT_VERSION_OBSOLETE)
+ and (args.filter_type == "obsolete" or args.filter_type == "all")):
+ action = "obsolete"
+ else:
+ return
+
+ template_data[suite]['counter'] += 1
+
+ tmp = template_data[suite]['rawelement'].replace('{%PT_ITEM_INDEX/%}',
+ str(template_data[suite]['counter']))
+ tmp = tmp.replace('{%PT_SOURCE_PACKAGE/%}',
+ query_cache[package].versions[0].source_name)
+ tmp = tmp.replace('{%PT_PARENT_VERSION/%}',
+ compare_cache[package].versions[0].source_version)
+ tmp = tmp.replace('{%PT_CURRENT_VERSION/%}',
+ query_cache[package].versions[0].source_version)
+ tmp = tmp.replace('{%PT_STATUS/%}',
+ action)
+
+ template_data[suite]['elements'] += tmp
+
+def output_template():
+ """ Outputs a file with the generated results """
+ global args
+ global template_rawdata, template_data
+ global install_path, config_path
+
+
+ #FIXME: usage of apt functions to query archives in use
+ f = open(os.path.join(install_path, args.READ), 'r')
+ configured_archives_query = f.read()
+ f.close()
+ configured_archives_query = re.sub(r"^\W?#.+?$\n?", "",
+ configured_archives_query, flags=re.MULTILINE)
+ configured_archives_query = re.sub(r"^\W?$\n?", "",
+ configured_archives_query, flags=re.MULTILINE)
+
+ f = open(os.path.join(install_path, args.COMPARE), 'r')
+ configured_archives_compare = f.read()
+ f.close()
+ configured_archives_compare = re.sub(r"^\W?#.+?$\n?", "",
+ configured_archives_compare, flags=re.MULTILINE)
+ configured_archives_compare = re.sub(r"^\W?$\n?", "",
+ configured_archives_compare, flags=re.MULTILINE)
+
+ title = "Package-Tracker Report"
+ intro = "<h1>" + title + "</h1>\n"
+ intro += "<p>This Report was generated at: " + time.ctime() + "</p>\n"
+ intro += "<p>"
+ if ((args.filter_type == "lower") or (args.filter_type == "all")):
+ intro += "Total of source packages wich are outdated: "
+ intro += str(update_counter) + "<br/>\n"
+ if ((args.filter_type == "obsolete") or (args.filter_type == "all")):
+ intro += "Total of source packages wich are obsolete: "
+ intro += str(obsolete_counter) + "<br/>\n"
+ if ((args.filter_type == "ok") or (args.filter_type == "all")):
+ intro += "Total of source packages with no action requested: "
+ intro += str(equal_counter) + "<br/>\n"
+ intro += "</p>"
+
+ summary = "Archives were read from:\n<pre>\n"
+ summary += configured_archives_query + "</pre>\n"
+ summary += "Archives wich have been compared against:\n<pre>\n"
+ summary += configured_archives_compare + "</pre>\n"
+
+ if (template_data['main']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_MAIN%}(.+?){%/PT_CONTENT_SPAN_MAIN%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_MAIN%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_MAIN%}(.+?){%/PT_CONTENT_ELEMENTS_MAIN%}'
+ template_rawdata = re.sub(re_element, template_data['main']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ if (template_data['security']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_SECURITY%}(.+?){%/PT_CONTENT_SPAN_SECURITY%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_SECURITY%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_SECURITY%}(.+?){%/PT_CONTENT_ELEMENTS_SECURITY%}'
+ template_rawdata = re.sub(re_element, template_data['security']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ if (template_data['updates']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_UPDATES%}(.+?){%/PT_CONTENT_SPAN_UPDATES%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_UPDATES%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_UPDATES%}(.+?){%/PT_CONTENT_ELEMENTS_UPDATES%}'
+ template_rawdata = re.sub(re_element, template_data['updates']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ if (template_data['extras']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_EXTRAS%}(.+?){%/PT_CONTENT_SPAN_EXTRAS%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_EXTRAS%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_EXTRAS%}(.+?){%/PT_CONTENT_ELEMENTS_EXTRAS%}'
+ template_rawdata = re.sub(re_element, template_data['extras']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ if (template_data['backports']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_BACKPORTS%}(.+?){%/PT_CONTENT_SPAN_BACKPORTS%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_BACKPORTS%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_BACKPORTS%}(.+?){%/PT_CONTENT_ELEMENTS_BACKPORTS%}'
+ template_rawdata = re.sub(re_element, template_data['backports']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ if (template_data['backports-extras']['counter'] == 0):
+ re_element = r'{%PT_CONTENT_SPAN_BACKPORTSEXTRAS%}(.+?){%/PT_CONTENT_SPAN_BACKPORTSEXTRAS%}'
+ else:
+ template_rawdata = re.sub(r'{%[/]*PT_CONTENT_SPAN_BACKPORTSEXTRAS%}', '',
+ template_rawdata, flags=re.DOTALL)
+ re_element = r'{%PT_CONTENT_ELEMENTS_BACKPORTSEXTRAS%}(.+?){%/PT_CONTENT_ELEMENTS_BACKPORTSEXTRAS%}'
+ template_rawdata = re.sub(re_element, template_data['backports-extras']['elements'],
+ template_rawdata, flags=re.DOTALL)
+
+ #FIXME: Cleanup of unmatched tags from template
+
+
+ # replace single items
+ template_rawdata = template_rawdata.replace('{%PT_TITLE/%}', title)
+ template_rawdata = template_rawdata.replace('{%PT_INTRO/%}', intro)
+ template_rawdata = template_rawdata.replace('{%PT_SUMMARY/%}', summary)
+
+ file_name = args.file_path
+ f = open(file_name, "w")
+ f.write(template_rawdata)
+ f.close()
+
+# --------------------------------
+# Apt cache packages processing
+#
+compare_data = {}
+query_data = {}
+suites = [
+ 'main',
+ 'security',
+ 'updates',
+ 'extras',
+ 'backports',
+ 'backports-extras'
+ ]
+
+# FIXME: debug
+def debug_data():
+ for source_package, binary_packages in compare_data.items():
+ print("source: ", source_package)
+ for binary_package in binary_packages:
+ print(" binary: ", binary_package)
+
+def process_packages():
+ """ Read all packages in compare cache to detect source/binary packages """
+ global query_data
+ global compare_data
+
+ for package in compare_cache:
+ archive = package.versions[0].origins[0].archive
+ if (not archive in compare_data):
+ compare_data[archive] = {}
+ if (not package.versions[0].source_name in compare_data[archive]):
+ compare_data[archive][package.versions[0].source_name] = []
+
+ compare_data[archive][package.versions[0].source_name].append(package.shortname)
+
+ for package in query_cache:
+ archive = package.versions[0].origins[0].archive
+ if (not archive in query_data):
+ query_data[archive] = {}
+ if (not package.versions[0].source_name in query_data[archive]):
+ query_data[archive][package.versions[0].source_name] = []
+
+ query_data[archive][package.versions[0].source_name].append(package.shortname)
+
+def process_compared_data():
+ """
+ Iterate over all source packages and process
+ the compare result data from process_packages()
+ """
+ global equal_conter, update_counter, obsolete_counter
+
+ # check if we have to compare against
+ # or from a testing archive
+ compare_archive = "stable"
+ if (not compare_archive in compare_data):
+ compare_archive = "testing"
+ if (not compare_archive in compare_data):
+ logging.error("There is no testing or stable suite in parent distribution.")
+ sys.exit(1)
+ query_archive = "stable"
+ if (not query_archive in query_data):
+ query_archive = "testing"
+ if (not query_archive in query_data):
+ logging.error("There is no testing or stable suite in current distribution.")
+ sys.exit(1)
+
+ for suite in suites:
+ if (suite != 'main'):
+ if (suite == 'backports' or suite == 'backports-extras'):
+ compare_suite = 'unstable'
+ else:
+ compare_suite = compare_archive + "-" + suite
+ if (not compare_suite in compare_data):
+ logging.info("skipping check for '" + suite + "'. It does not exist in parent archives.")
+ continue
+ query_suite = query_archive + "-" + suite
+ if (not query_suite in query_data):
+ logging.info("skipping check for '" + suite + "'. It does not exist in current archives.")
+ continue
+ else:
+ compare_suite = compare_archive
+ query_suite = query_archive
+
+ #FIXME: stdout output
+ if (args.output_type == "stdout"):
+ print()
+ print("comparing '" + query_suite + "' against '" + compare_suite + "' suite")
+
+ for source_package in compare_data[compare_suite]:
+ if (source_package in query_data[query_suite]):
+ for binary_package in compare_data[compare_suite][source_package]:
+ if (binary_package in query_data[query_suite]):
+ result = compare_versions(
+ query_cache[binary_package].versions[0].version,
+ compare_cache[binary_package].versions[0].version)
+
+ # FIXME: testing
+ # Check if compare_result has errors
+ if (result == PT_VERSION_COMPARE_ERROR):
+ logging.error(
+ "compare_result for " + binary_package.shortname + " has not succeeded."
+ )
+ if (args.debug):
+ logging.debug(
+ "source package: "
+ + query_cache[source_package].shortname
+ + " "
+ + query_cache[source_package].versions[0].source_version
+ + " (current) "
+ + compare_cache[source_package].versions[0].source_version
+ + " (parent)"
+ )
+ logging.debug(
+ "binary package: "
+ + query_cache[binary_package].shortname
+ )
+ logging.debug(
+ "current binary version: "
+ + query_cache[binary_package].versions[0].version
+ )
+ logging.debug(
+ "parent binary version: "
+ + compare_cache[binary_package].versions[0].version
+ )
+ compare_debug(result)
+
+ if (args.output_type == "stdout"):
+ print_package_message(source_package, result)
+ else:
+ add_template_element(suite, source_package, result)
+
+ #Check for extras and backports-extras source packages
+ #wich have a package in parent archive
+ for suite in [ 'extras', 'backports-extras' ]:
+ #FIXME: stdout output
+ if (args.output_type == "stdout"):
+ print()
+ print("obsolete check for '" + query_archive + "-" + suite + "'")
+
+ if query_archive + "-" + suite in query_data:
+ for source_package in query_data[query_archive + "-" + suite]:
+ if (source_package in compare_cache):
+ obsolete_counter += 1
+
+ if (args.debug):
+ logging.debug(
+ "obsolete-check: source package: "
+ + query_cache[source_package].shortname
+ + " "
+ + query_cache[source_package].versions[0].version
+ + " (current) is obsolete"
+ )
+ logging.debug(
+ "obsolete-check: parent source version: "
+ + compare_cache[source_package].versions[0].source_version
+ )
+
+ if (args.output_type == "stdout"):
+ print_package_message(source_package, PT_VERSION_OBSOLETE)
+ else:
+ add_template_element(suite, source_package, PT_VERSION_OBSOLETE)
+
+
+# --------------------------------
+# Main:
+#
+def main():
+ global query_cache
+ global compare_cache
+ global install_path
+ global apt_root_path
+ global args
+
+ # Configuring logging
+ if (args.verbose == True):
+ loglevel=logging.DEBUG
+ else:
+ loglevel=logging.INFO
+
+ logging.basicConfig(
+ filename=os.path.join(install_path, log_file),
+ level=loglevel,
+ filemode='w',
+ format="%(asctime)s: "+software+": %(levelname)s: %(message)s"
+ )
+
+ if (args.verbose == True):
+ print("Reading apt archives to compare from..")
+
+ relink_sources_file(args.READ)
+
+ query_cache = apt.Cache(rootdir=os.path.join(install_path, apt_root_path))
+ query_cache.update(None)
+ query_cache.open()
+
+ if (args.verbose == True):
+ print("Reading apt archives to compare against..")
+
+ relink_sources_file(args.COMPARE)
+
+ compare_cache = apt.Cache(rootdir=os.path.join(install_path, apt_root_path))
+ compare_cache.update(None)
+ compare_cache.open()
+
+ if (args.verbose == True):
+ print()
+ print(
+ "Number of packages in archives to compare from: ",
+ len(query_cache)
+ )
+ print(
+ "Number of packages to compare against: ",
+ len(compare_cache)
+ )
+ print()
+ print("Comparing packages..")
+
+ process_packages()
+
+ if (args.verbose == True):
+ print(
+ "Source packages to compare: ",
+ len(compare_data)
+ )
+
+ if (args.output_type == "html"):
+ load_template()
+
+ process_compared_data()
+
+ if (args.output_type == "html"):
+ output_template()
+
+ if (args.verbose == True):
+ print()
+ print(
+ "Total of source packages to update: ",
+ update_counter
+ )
+ print(
+ "Total of source packages wich are obsolete: ",
+ obsolete_counter
+ )
+ print(
+ "Total of source packages with no action required: ",
+ equal_counter
+ )
+
+
+if (__name__ == "__main__"):
+ main()
+
+sys.exit(0)