From 4041174dc030925a69b05c5caa8dec17a1b9154d Mon Sep 17 00:00:00 2001
From: Adam Števko <xen0l@users.noreply.github.com>
Date: Fri, 19 Oct 2018 19:15:41 +0200
Subject: [PATCH] Generate a component mapping file (#4534)

---
 tools/userland-mangler      |    4 
 tools/userland-mapping      |  111 +++++++++++++++++++++++++++++++++++++
 make-rules/shared-macros.mk |    7 ++
 components/Makefile         |   11 +++
 4 files changed, 129 insertions(+), 4 deletions(-)

diff --git a/components/Makefile b/components/Makefile
index 87f38be..2c7a446 100644
--- a/components/Makefile
+++ b/components/Makefile
@@ -52,6 +52,12 @@
 
 -include $(WS_TOP)/components/$(ENCUMBERED)depends.mk
 
+# component_mapping.json is auto-generated by the build tools. It provides a map
+# between component path and component FMRI.
+$(WS_TOP)/components/mapping.json:
+	@echo "Generating component mapping..."
+	@$(WS_TOOLS)/userland-mapping --workspace=$(WS_TOP)
+mapping.json: $(WS_TOP)/components/mapping.json
 
 download:		TARGET = download
 prep:			TARGET = prep
@@ -82,7 +88,10 @@
 component-hook:	$(COMPONENT_DIRS.nosetup)
 
 clean:		$(COMPONENT_DIRS.nosetup)
-	$(RM) $(WS_TOP)/components/$(ENCUMBERED)components.mk $(WS_TOP)/components/$(ENCUMBERED)depends.mk .profile
+	$(RM) $(WS_TOP)/components/$(ENCUMBERED)components.mk \
+	$(WS_TOP)/components/$(ENCUMBERED)depends.mk \
+	$(WS_TOP)/components/mapping.json \
+	.profile
 
 clobber:	$(COMPONENT_DIRS.nosetup) clean
 	@cd $(WS_TOP)/tools ; echo "clobbering tools..." ; $(GMAKE) clobber
diff --git a/make-rules/shared-macros.mk b/make-rules/shared-macros.mk
index 32d172a..e2b3380 100644
--- a/make-rules/shared-macros.mk
+++ b/make-rules/shared-macros.mk
@@ -647,7 +647,7 @@
 FC =		$(FC.$(COMPILER).$(BITS))
 
 RUBY_VERSION =  2.3
-RUBY_LIB_VERSION.2.2 = 2.2.0	
+RUBY_LIB_VERSION.2.2 = 2.2.0
 RUBY_LIB_VERSION.2.3 = 2.3.0
 RUBY.2.2 =	/usr/ruby/2.2/bin/ruby
 RUBY.2.3 =	/usr/ruby/2.3/bin/ruby
@@ -1303,3 +1303,8 @@
 # is not always what you get.
 print-%:
 	@echo '$(subst ','\'',$*=$($*)) (origin: $(origin $*), flavor: $(flavor $*))'
+
+# A simple rule to print only the value of any macro.
+print-value-%:
+	@echo '$(subst ','\'',$($*))'
+
diff --git a/tools/userland-mangler b/tools/userland-mangler
index 761ac81..c8da3dd 100755
--- a/tools/userland-mangler
+++ b/tools/userland-mangler
@@ -64,7 +64,7 @@
 Stability	%s"""
 
 attribute_table_footer = """
-.TE 
+.TE
 .PP
 """
 def attributes_section_text(availability, stability, modified_date):
@@ -344,7 +344,7 @@
 def main():
 	import getopt
 
-	# FLUSH STDOUT 
+	# FLUSH STDOUT
 	sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
 
 	search_paths = []
diff --git a/tools/userland-mapping b/tools/userland-mapping
new file mode 100755
index 0000000..899ccc7
--- /dev/null
+++ b/tools/userland-mapping
@@ -0,0 +1,111 @@
+#!/usr/bin/python2.7
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Adam Stevko
+#
+
+#
+# mapping.py - generate mapping between component FMRI and component package names, to be used for different purposes,
+# e.g. checking for outdated pacakges, vulnerable packages etc.
+#
+
+from __future__ import print_function, absolute_import
+
+import argparse
+import json
+import os
+import re
+import logging
+import subprocess
+import multiprocessing
+import sys
+
+try:
+    from scandir import walk
+except ImportError:
+    from os import walk
+
+logger = logging.getLogger('userland-mapping')
+
+COMONENT_MAPPING_FILENAME = 'mapping.json'
+
+
+def find_component_paths(path, subdir='components', debug=False):
+    expression = re.compile(r'.+\.p5m$', re.IGNORECASE)
+
+    paths = []
+    workspace_path = os.path.join(path, subdir)
+
+    for dirpath, dirnames, filenames in walk(workspace_path):
+        for name in filenames:
+            if expression.match(name):
+                paths.append(dirpath)
+                del dirnames[:]
+                break
+
+    return paths
+
+
+def generate_component_data(component_path):
+    result = []
+
+    proc = subprocess.Popen(['gmake', 'print-value-COMPONENT_NAME', 'print-package-names'],
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE,
+                            cwd=component_path)
+
+    for out in proc.stdout:
+        result.append(out.rstrip())
+
+    component_name = result[0]
+    component_fmris = result[1:]
+    component_relative_path = component_path.split(os.environ['WS_TOP'])[-1].replace('/', '', 1)
+
+    return component_fmris, component_name, component_relative_path
+
+
+def generate_userland_mapping(workspace_path, subdir='components'):
+    mapping = []
+
+    paths = find_component_paths(path=workspace_path, subdir=subdir)
+    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
+    results = pool.map(generate_component_data, paths)
+
+    for component_fmris, component_name, component_relative_path in results:
+        for component_fmri in component_fmris:
+            mapping.append({'component_name': component_name,
+                            'component_fmri': component_fmri,
+                            'component_path': component_relative_path})
+
+    component_mapping_file = os.path.join(workspace_path, subdir, COMONENT_MAPPING_FILENAME)
+    with open(component_mapping_file, 'w') as f:
+        f.write(json.dumps(mapping, sort_keys=True, indent=4))
+
+
+def main():
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('-w', '--workspace', default=os.getenv('WS_TOP'), help='Path to workspace')
+    parser.add_argument('--subdir', default='components', help='Directory holding components')
+
+    args = parser.parse_args()
+
+    workspace = args.workspace
+    subdir = args.subdir
+
+    generate_userland_mapping(workspace_path=workspace, subdir=subdir)
+
+
+if __name__ == '__main__':
+    main()

--
Gitblit v1.9.3