From da4cca4b4c33c4a1779c708a9cfaaa6413536939 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Aug 26 2017 13:46:03 +0000 Subject: [PATCH 1/7] nodejs.prov: account for bundled libraries Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.prov b/nodejs.prov index 7c8dac2..ac4ac71 100755 --- a/nodejs.prov +++ b/nodejs.prov @@ -6,6 +6,7 @@ Automatic provides generator for Node.js libraries. Taken from package.json. See `man npm-json` for details. """ # Copyright 2012 T.C. Hollingsworth +# Copyright 2017 Tomas Tomecek # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -25,21 +26,51 @@ Taken from package.json. See `man npm-json` for details. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -import json +from __future__ import print_function + +import os import sys +import json + + +def handle_package_json(path, bundled=False): + """ + process package.json file available on path, print RPM dependency based on name and version + """ + if not path.endswith('package.json') or not os.path.isfile(path): + return + fh = open(path) + metadata = json.load(fh) + fh.close() + + if 'name' in metadata and not ('private' in metadata and metadata['private']): + if bundled: + value = "bundled(nodejs-%s) = %s" % (metadata["name"], metadata["version"]) + else: + value = "npm(%s) = %s" % (metadata["name"], metadata["version"]) + print(value) + + +def handle_module(path, bundled): + """ + process npm module and all its bundled dependencies + """ + handle_package_json(path, bundled=bundled) + if not os.path.isdir(path): + path = os.path.dirname(path) + node_modules_dir_candidate = os.path.join(path, "node_modules") + if os.path.isdir(node_modules_dir_candidate): + for module_path in os.listdir(node_modules_dir_candidate): + p_json_file = os.path.join(node_modules_dir_candidate, module_path, "package.json") + handle_module(p_json_file, bundled=True) + -paths = [path.rstrip() for path in sys.stdin.readlines()] +def main(): + paths = [path.rstrip() for path in sys.stdin.readlines()] -for path in paths: - if path.endswith('package.json'): - fh = open(path) - metadata = json.load(fh) - fh.close() + for path in paths: + handle_module(path, bundled=False) - if 'name' in metadata and not ('private' in metadata and metadata['private']): - print 'npm(' + metadata['name'] + ')', - if 'version' in metadata: - print '= ' + metadata['version'] - else: - print +if __name__ == '__main__': + main() From 1bd5ec9e26fddf0f0653317bf9a5c6ef3ebc65b7 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Sep 10 2017 08:48:43 +0000 Subject: [PATCH 2/7] Add sorting and uniqueness for bundled provides --- diff --git a/nodejs.prov b/nodejs.prov index ac4ac71..1d06fbd 100755 --- a/nodejs.prov +++ b/nodejs.prov @@ -32,6 +32,7 @@ import os import sys import json +provides = set() def handle_package_json(path, bundled=False): """ @@ -48,7 +49,7 @@ def handle_package_json(path, bundled=False): value = "bundled(nodejs-%s) = %s" % (metadata["name"], metadata["version"]) else: value = "npm(%s) = %s" % (metadata["name"], metadata["version"]) - print(value) + provides.add(value) def handle_module(path, bundled): @@ -71,6 +72,9 @@ def main(): for path in paths: handle_module(path, bundled=False) + for provide in sorted(provides): + print(provide) + if __name__ == '__main__': main() From 1ddf945027f2093d04af1b23fee38bc82f546674 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Sep 10 2017 08:54:08 +0000 Subject: [PATCH 3/7] skip dep if name or version is not specified Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.prov b/nodejs.prov index 1d06fbd..74b07ae 100755 --- a/nodejs.prov +++ b/nodejs.prov @@ -44,12 +44,26 @@ def handle_package_json(path, bundled=False): metadata = json.load(fh) fh.close() - if 'name' in metadata and not ('private' in metadata and metadata['private']): - if bundled: - value = "bundled(nodejs-%s) = %s" % (metadata["name"], metadata["version"]) - else: - value = "npm(%s) = %s" % (metadata["name"], metadata["version"]) - provides.add(value) + try: + if metadata['private']: + return + except KeyError: + pass + + try: + name = metadata["name"] + except KeyError: + return + try: + version = metadata["version"] + except KeyError: + return + + if bundled: + value = "bundled(nodejs-%s) = %s" % (name, version) + else: + value = "npm(%s) = %s" % (name, version) + provides.add(value) def handle_module(path, bundled): From 97bf5dfd83446604c0bf7430b4af1e8a71bea5d1 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Sep 10 2017 09:04:07 +0000 Subject: [PATCH 4/7] nodejs.prov: document input of the script Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.prov b/nodejs.prov index 74b07ae..fd25f8a 100755 --- a/nodejs.prov +++ b/nodejs.prov @@ -81,6 +81,7 @@ def handle_module(path, bundled): def main(): + """ read list of package.json paths from stdin """ paths = [path.rstrip() for path in sys.stdin.readlines()] for path in paths: From f378cabb787568f3c6d010da6b7791cad4e63d86 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Sep 10 2017 10:37:12 +0000 Subject: [PATCH 5/7] nodejs.req: whitespace Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.req b/nodejs.req index e4b1e30..f60def3 100755 --- a/nodejs.req +++ b/nodejs.req @@ -17,7 +17,7 @@ Parsed from package.json. See `man npm-json` for details. # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -84,21 +84,21 @@ def main(): def process_dep(req, version): """Converts an individual npm dependency into RPM dependencies""" - + deps = [] - + #there's no way RPM can do anything like an OR dependency if '||' in version: sys.stderr.write("WARNING: The {0} dependency contains an ".format(req) + "OR (||) dependency: '{0}.\nPlease manually include ".format(version) + "a versioned dependency in your spec file if necessary") deps.append(req) - + elif ' - ' in version: gt, lt = version.split(' - ') deps.append(req + ' >= ' + gt) deps.append(req + ' <= ' + lt) - + else: m = re.match(RE_VERSION, version) @@ -115,10 +115,10 @@ def process_dep(req, version): deps.append(req) return deps - + def convert_dep(req, operator, version): """Converts one of the two possibly listed versions into an RPM dependency""" - + deps = [] #any version will do @@ -164,14 +164,14 @@ def convert_dep(req, operator, version): elif operator == '~': deps.append('{0} >= {1}'.format(req, version)) deps.append('{0} < {1}'.format(req, parts[0]+1)) - + #^1.2 elif operator == '^': deps.append('{0} >= {1}'.format(req, version)) deps.append('{0} < {1}'.format(req, parts[0]+1)) - + return deps - + if __name__ == '__main__': main() From 1d6bd8412cf0e4c73fdd843b600dbca880cc019a Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Sep 10 2017 10:51:05 +0000 Subject: [PATCH 6/7] nodejs.{prov,req}: skip if bundled module is a symlink This commit accounts for 2 use cases: * all modules in node_modules/ are symlinks -- nodejs.prov and .req correctly require appropriate rpm and don't print any of the modules as bundled * modules in node_modules/ bundled -- nodejs.prov prints these modules as bundled Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.prov b/nodejs.prov index fd25f8a..811e7cc 100755 --- a/nodejs.prov +++ b/nodejs.prov @@ -76,8 +76,11 @@ def handle_module(path, bundled): node_modules_dir_candidate = os.path.join(path, "node_modules") if os.path.isdir(node_modules_dir_candidate): for module_path in os.listdir(node_modules_dir_candidate): - p_json_file = os.path.join(node_modules_dir_candidate, module_path, "package.json") - handle_module(p_json_file, bundled=True) + module_abs_path = os.path.join(node_modules_dir_candidate, module_path) + # skip modules which are linked against system module + if not os.path.islink(module_abs_path): + p_json_file = os.path.join(module_abs_path, "package.json") + handle_module(p_json_file, bundled=True) def main(): diff --git a/nodejs.req b/nodejs.req index f60def3..aa36bcf 100755 --- a/nodejs.req +++ b/nodejs.req @@ -28,11 +28,23 @@ Parsed from package.json. See `man npm-json` for details. from __future__ import unicode_literals import json +import os import re import sys RE_VERSION = re.compile(r'\s*v?([<>=~^]{0,2})\s*([0-9][0-9\.\-]*)\s*') +def has_all_bundled(path): + # remove 'package.json' + path = os.path.dirname(path) + node_modules_dir_candidate = os.path.join(path, "node_modules") + if os.path.isdir(node_modules_dir_candidate): + modules_abs_path = map(lambda x: os.path.join(node_modules_dir_candidate, x), + os.listdir(node_modules_dir_candidate)) + any_link = any([os.path.islink(x) for x in modules_abs_path]) + return not any_link + + def main(): #npm2rpm uses functions here to write BuildRequires so don't print anything #until the very end @@ -45,7 +57,10 @@ def main(): for path in paths: if not path.endswith('package.json'): continue - + + if has_all_bundled(path): + continue + fh = open(path) metadata = json.load(fh) fh.close() From af7f4fa9aac78baf6dc82f93aadbef3dcd4f2a09 Mon Sep 17 00:00:00 2001 From: Tomas Tomecek Date: Sep 10 2017 10:53:13 +0000 Subject: [PATCH 7/7] nodejs.req: use python 3 syntax Signed-off-by: Tomas Tomecek --- diff --git a/nodejs.req b/nodejs.req index aa36bcf..c89a2cd 100755 --- a/nodejs.req +++ b/nodejs.req @@ -26,7 +26,7 @@ Parsed from package.json. See `man npm-json` for details. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function import json import os import re @@ -95,7 +95,7 @@ def main(): else: raise TypeError('invalid package.json: dependencies not a valid type') - print '\n'.join(deps) + print('\n'.join(deps)) def process_dep(req, version): """Converts an individual npm dependency into RPM dependencies"""