summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-01-09 13:25:25 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-01-09 13:25:25 -0500
commit5fdbca629d6fbf4b6382ec70f5e20fe530566312 (patch)
tree4e7a46c3480df88f8c2801cc3576ff8d96b3dda1 /src
parentb114a76bede25432f1c9086d6ac657292673db9d (diff)
downloadpymkenv-5fdbca629d6fbf4b6382ec70f5e20fe530566312.tar.gz
Add tree output and argparse options
Diffstat (limited to 'src')
-rw-r--r--src/checkenv.py177
-rwxr-xr-xsrc/checkenv_resolver300
2 files changed, 300 insertions, 177 deletions
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 <jhunk at stsci.edu>
+# 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)