Marcel Telka
2024-04-08 5d8bcb58722b250c296fc0324f9d06470fb3d7d0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/python3.5
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright (c) 2010, Oracle and/or it's affiliates.  All rights reserved.
#
#
# bass-o-matic.py
#  A simple program to enumerate components in the userland gate and report
#  on dependency related information.
#
 
import os
import subprocess
import json
 
class Component(object):
    def __init__(self, path=None, debug=False):
        self.debug = debug
        self.path = path
        self.name = None
        self.supplied_packages = []
        self.required_packages = []
        if path:
            component_pkg5_file = os.path.join(self.path, 'pkg5')
            if not os.path.isfile(component_pkg5_file):
                # get component name
                component_name = self.run_make(path, 'print-value-COMPONENT_NAME')
                if not component_name:
                    raise ValueError('Component returns empty name at ' + self.path + '.')
                else:
                    self.name = component_name[0]
                # get supplied packages, this may trigger the creation of a pkg5.fmris file
                self.supplied_packages = self.run_make(path, 'print-package-names')
                # always update fmris if list is overriden
                component_pkg5_fmris_file = os.path.join(self.path, 'pkg5.fmris')
                if os.path.isfile(component_pkg5_fmris_file):
                    with open(component_pkg5_fmris_file, 'r') as f:
                        self.supplied_packages = f.read().splitlines()
 
                # get dependencies
                self.required_packages = self.run_make(path, 'print-required-packages')
 
                data = { 'name' : self.name,
                         'fmris': self.supplied_packages,
                         'dependencies' : self.required_packages }
                with open(component_pkg5_file, 'w') as f:
                    f.write(json.dumps(data, sort_keys=True, indent=4))
                    f.write('\n')
            else:
                with open(component_pkg5_file, 'r') as f:
                    data = json.loads(f.read())
                if not data:
                    raise ValueError('Component pkg5 data is empty for path ' + self.path + '.')
                self.name = data['name']
                self.supplied_packages = data['fmris']
                self.required_packages = data['dependencies']
 
    def required(self, component):
        result = False
 
        s1 = set(self.required_packages)
        s2 = set(component.supplied_packages)
        if s1.intersection(s2):
            result = True
 
        return result
 
    def run_make(self, path, targets):
 
        result = []
 
        if self.debug:
            logger.debug('Executing \'gmake %s\' in %s', targets, path)
 
        proc = subprocess.Popen(['gmake', '-s', targets],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                cwd=path,
                                universal_newlines=True)
        stdout, stderr = proc.communicate()
 
        for out in stdout.splitlines():
            result.append(out.rstrip())
 
        if self.debug:
            if proc.returncode != 0:
                logger.debug('exit: %d, %s', proc.returncode, stderr)
 
        return result
 
    def __str__(self):
        result = 'Component:\n\tPath: %s\n' % self.path
        result += '\tProvides Package(s):\n\t\t%s\n' % '\t\t'.join(self.supplied_packages)
        result += '\tRequired Package(s):\n\t\t%s\n' % '\t\t'.join(self.required_packages)
 
        return result