From 5fdbca629d6fbf4b6382ec70f5e20fe530566312 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 9 Jan 2015 13:25:25 -0500 Subject: Add tree output and argparse options --- src/checkenv.py | 177 ----------------------------- src/checkenv_resolver | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+), 177 deletions(-) delete mode 100644 src/checkenv.py create mode 100755 src/checkenv_resolver (limited to 'src') diff --git a/src/checkenv.py b/src/checkenv.py deleted file mode 100644 index 5e17c9d..0000000 --- a/src/checkenv.py +++ /dev/null @@ -1,177 +0,0 @@ -import os -from pprint import pprint -from string import Template -from collections import deque - - -class PackagePrioritizer(object): - def __init__(self): - self.weight = {} - self.packages = [] - - def insert(self, package): - self.packages.append(package) - - def generate_weightmap(self): - self.weight = { str(x):[] for x in self.packages } - for package in self.packages: - for priority in package.precedence: - self.weight[str(package)].append(priority.name) - - -class PackageException(Exception): - pass - -class Package(object): - def __init__(self, filename, load=True): - self.valid_keywords = [ - 'Type', - 'Requires', - 'Precedes', - 'Synopsis', - 'Description', - 'Environment', - 'LdLibrary', - 'IncPath', - 'Root', - 'Path', - 'ManPath', - 'Default', - 'Source' - ] - self.filename = os.path.join(ENVCONFIG_PATH, filename) - self.exists = False - self.name = '' - self.name_internal = '' - self.description = '' - self.dependencies = [] - self.precedence = [] - self.priority = 0 # 0 - 99 - self.shell = '' - self.env = {} - self.script = '' - self.invisible = False - self.mtime = 0 - self.data = {} - - if os.path.exists(self.filename): - self.exists = True - - self.name = os.path.basename(self.filename.replace(' ', '_')) - - if not load: - return - - if self.filename is not None \ - and self.exists: - self.data = self.load() - self.get_requirements() - self.get_precedence() - - def __repr__(self): - return self.name - - def get_requirements(self): - if not self.data: - raise PackageException('Package data not loaded.') - - if 'Requires' in self.data: - for next_req in self.data['Requires']: - req = Package(next_req) - self.dependencies.append(req) - if not req.exists: - print("Requirement warning, {}: {} does not exist".format(self.name, os.path.basename(req.filename))) - - def get_precedence(self): - if not self.data: - raise PackageException('Package data not loaded.') - - if 'Precedes' in self.data: - for next_req in self.data['Precedes']: - req = Package(next_req, load=False) - self.precedence.append(req) - if not req.exists: - print("Precedence warning, {}: {} does not exist".format(self.name, os.path.basename(req.filename))) - - - def load(self): - pairs = [] - comment = '#' - delimiter = ':' - keyword = '' - value = '' - - with open(self.filename, 'r') as f: - for line in f.readlines(): - line = line.strip() - if not line: - continue - if not line.find(delimiter): - continue - if line.startswith(comment): - continue - - keyword = line[0:line.find(delimiter)] - if keyword not in self.valid_keywords: - continue - if keyword == 'Source': - continue - - value = line[line.find(delimiter) + 1:].strip() - pairs.append([keyword, value]) - - # Do source block - with open(self.filename, 'r') as f: - value = '' - shell_type = '' - data_block = False - - for line in f.readlines(): - if line.startswith('Source:'): - data_block = True - shell_type = line[line.find(delimiter) + 1:line.rfind(delimiter)].strip() - line = line[line.rfind(delimiter) + 1:-1] - if data_block: - value += line - if line.startswith('"') and line.endswith('\\'): - data_block = False - - pairs.append(['Source', value]) - pairs.append(['Shell', shell_type]) - - pairs = dict(pairs) - - # Alias the filename to be the same as "Root" value - if 'Root' in pairs: - pairs[self.name] = pairs['Root'] - - # Substitute configuration values - for key, value in pairs.items(): - s = Template(value) - pairs[key] = s.safe_substitute(pairs) - - if 'Requires' in pairs: - pairs['Requires'] = str(pairs['Requires']).split() - - if 'Precedes' in pairs: - pairs['Precedes'] = str(pairs['Precedes']).split() - - return dict(pairs) - -if __name__ == '__main__': - ENVCONFIG_PATH = os.path.abspath(os.path.normpath('../envconfig')) - - pkgs = [] - for r, d, fs in os.walk(ENVCONFIG_PATH): - for f in fs: - pkgs.append(Package(f)) - #pkg = Package('JDK1.6.07') - pp = PackagePrioritizer() - for pkg in pkgs: - pp.insert(pkg) - - pp.generate_weightmap() - pprint(pp.weight) - #pprint(pp.packages) - #pkg = Package(None) - #pprint(pkg.data) diff --git a/src/checkenv_resolver b/src/checkenv_resolver new file mode 100755 index 0000000..6ebabaf --- /dev/null +++ b/src/checkenv_resolver @@ -0,0 +1,300 @@ +#!/usr/bin/env python +# Copyright (c) 2015, Joseph Hunkeler +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +try: + import argparse +except ImportError: + print("Please install argparse.") + exit(1) + +import os +import sys +from string import Template + + +class PackageException(Exception): + pass + +class Package(object): + def __init__(self, filename, load=True): + self.valid_keywords = [ + 'Type', + 'Requires', + 'Precedes', + 'Synopsis', + 'Description', + 'Environment', + 'LdLibrary', + 'IncPath', + 'Root', + 'Path', + 'ManPath', + 'Default', + 'Source' + ] + self.filename = os.path.join(ENVCONFIG_PATH, filename) + self.exists = False + self.name = '' + self.name_internal = '' + self.description = '' + self.dependencies = [] + self.precedence = [] + self.priority = 0 # 0 - 99 + self.shell = '' + self.env = {} + self.script = '' + self.invisible = False + self.mtime = 0 + self.data = {} + self.verbose = False + + if not load: + return + + self.preload() + + def __repr__(self): + return self.name + + def preload(self): + if os.path.exists(self.filename): + self.exists = True + + self.name = os.path.basename(self.filename.replace(' ', '_')) + + if self.filename is not None \ + and self.exists: + self.data = self.load() + self.get_requirements() + self.get_precedence() + + def get_requirements(self): + if not self.data: + PackageException('{0}: Package data not loaded.'.format(self.name)) + + if 'Requires' in self.data: + for next_req in self.data['Requires']: + try: + req = Package(next_req) + except: + continue + self.dependencies.append(req) + if not req.exists and self.verbose: + print("Requirement warning, {0}: {1} does not exist".format(self.name, os.path.basename(req.filename))) + + def get_precedence(self): + if not self.data: + raise PackageException('{0}: Package data not loaded.'.format(self.name)) + + if 'Precedes' in self.data: + for next_req in self.data['Precedes']: + req = Package(next_req, load=False) + self.precedence.append(req) + if not req.exists and self.verbose: + print("Precedence warning, {0}: {1} does not exist".format(self.name, os.path.basename(req.filename))) + + + def load(self): + pairs = [] + comment = '#' + delimiter = ':' + keyword = '' + value = '' + + with open(self.filename, 'r') as f: + for line in f.readlines(): + line = line.strip() + if not line: + continue + if not line.find(delimiter): + continue + if line.startswith(comment): + continue + + keyword = line[0:line.find(delimiter)] + if keyword not in self.valid_keywords: + continue + if keyword == 'Source': + continue + + value = line[line.find(delimiter) + 1:].strip() + pairs.append([keyword, value]) + + # Do source block + with open(self.filename, 'r') as f: + value = '' + shell_type = '' + data_block = False + + for line in f.readlines(): + if line.startswith('Source:'): + data_block = True + shell_type = line[line.find(delimiter) + 1:line.rfind(delimiter)].strip() + line = line[line.rfind(delimiter) + 1:-1] + if data_block: + value += line + if line.startswith('"') and line.endswith('\\'): + data_block = False + + pairs.append(['Source', value]) + pairs.append(['Shell', shell_type]) + + pairs = dict(pairs) + + # Alias the filename to be the same as "Root" value + if 'Root' in pairs: + pairs[self.name] = pairs['Root'] + + # Substitute configuration values + for key, value in pairs.items(): + s = Template(value) + pairs[key] = s.safe_substitute(pairs) + + if 'Requires' in pairs: + pairs['Requires'] = str(pairs['Requires']).split() + + if 'Precedes' in pairs: + pairs['Precedes'] = str(pairs['Precedes']).split() + + return dict(pairs) + + +spaces = '' +missing = ' Missing'.rjust(25, '.') +def solver(p, style='dependency'): + ''' Recursive package dependency resolver + ''' + flags = '' + tree = ' \\_' + resolver = p.dependencies + + if args.no_graphics: + tree = ' ' + + if style != 'dependency': + resolver = p.precedence + + # Wasn't planning on using a global here, but... recursion. + global spaces + global missing + for dep in resolver: + if not dep.exists: + flags = missing + print('{0} {1}{2:20s} {3}'.format(spaces, tree, dep.name, flags)) + flags = '' + if dep.dependencies: + spaces += ' ' + # Fall back in on yourself if there are more dependencies + # beyond the current 'dep' + solver(dep, style) + spaces = '' + +def show_package_map(packages, style='dependency'): + tree = '*--' + global missing + + if args.no_graphics: + tree = '' + + for pkg in pkgs: + flags = '' + if not pkg.exists: + flags = missing + print('{0}{1:22s} {2}'.format(tree, pkg.name, flags)) + solver(pkg, style) + print('') + + +if __name__ == '__main__': + args = None + ENVCONFIG_PATH = os.path.abspath('/usr/local/envconfig') + HOME = os.environ['HOME'] + ENVRC = os.path.join(HOME, '.envrc') + pkgs = [] + + parser = argparse.ArgumentParser() + parser.add_argument('-e', '--every', action='store_true', help='Generate map for all packages') + parser.add_argument('-r', '--requires', action='store_true', help='Omit package dependencies') + parser.add_argument('-p', '--precedence', action='store_true', help='Omit package precedence') + parser.add_argument('-w', '--warnings', action='store_true', help='No tree, only warnings') + parser.add_argument('-g', '--no-graphics', action='store_true', help='No tree characters') + + args = parser.parse_args() + + + if args.every: + for r, d, fs in os.walk(ENVCONFIG_PATH): + for f in fs: + pkgs.append(Package(f)) + else: + try: + with open(ENVRC, 'r') as fp: + for record in fp: + if record.startswith('#'): + continue + + if record.startswith('Package:'): + _, _, record = record.partition(':') + else: + continue + + record = record.strip() + pkgs.append(Package(record)) + except OSError as e: + print(e.message) + + if not args.requires and not args.precedence: + print('To see a summary of available options, issue -h or --help') + exit(0) + + if args.warnings: + for pkg in pkgs: + pkg.verbose = True + + if not pkg.exists: + # Normally the object performs its own checks to make sure + # it can read precedence, but we're overriding that functionality. + print('General failure, {0}: {1} does not exist'.format(pkg.name)) + + if args.requires: + pkg.get_requirements() + if args.precedence: + pkg.get_precedence() + + exit(0) + + if args.requires: + print("#### ####") + print("### Dependency Map ###") + print("#### ####") + show_package_map(pkgs) + print('') + + if args.precedence: + print("#### ####") + print("### Precedence Map ###") + print("#### ####") + show_package_map(pkgs, style='precedence') + print('') + + exit(0) -- cgit