8de3f91
#!/usr/bin/python3
8de3f91
8de3f91
"""Symlink a node module's dependencies into the node_modules directory so users
8de3f91
can `npm link` RPM-installed modules into their personal projects."""
8de3f91
8de3f91
# Copyright 2012, 2013 T.C. Hollingsworth <tchollingsworth@gmail.com>
8de3f91
#
8de3f91
# Permission is hereby granted, free of charge, to any person obtaining a copy
8de3f91
# of this software and associated documentation files (the "Software"), to
8de3f91
# deal in the Software without restriction, including without limitation the
8de3f91
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8de3f91
# sell copies of the Software, and to permit persons to whom the Software is
8de3f91
# furnished to do so, subject to the following conditions:
8de3f91
#
8de3f91
# The above copyright notice and this permission notice shall be included in
8de3f91
# all copies or substantial portions of the Software.
8de3f91
#
8de3f91
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8de3f91
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8de3f91
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8de3f91
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8de3f91
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
8de3f91
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
8de3f91
# IN THE SOFTWARE.
8de3f91
8de3f91
import json
8de3f91
import os
8de3f91
import re
8de3f91
import shutil
8de3f91
import sys
8de3f91
8de3f91
def symlink(source, dest):
8de3f91
    try:
8de3f91
        os.symlink(source, dest)
8de3f91
    except OSError:
8de3f91
        if os.path.islink(dest) and os.path.realpath(dest) == os.path.normpath(source):
8de3f91
            sys.stderr.write("""
8de3f91
WARNING: the symlink for dependency "{0}" already exists
8de3f91
8de3f91
This could mean that the dependency exists in both devDependencies and 
8de3f91
dependencies, which may cause trouble for people using this module with npm.
8de3f91
8de3f91
Please report this to upstream. For more information, see:
8de3f91
    <https://github.com/tchollingsworth/nodejs-packaging/pull/1>
8de3f91
""".format(dest))
8de3f91
            
8de3f91
        elif '--force' in sys.argv:
8de3f91
            if os.path.isdir(dest):
8de3f91
                shutil.rmtree(dest)
8de3f91
            else:
8de3f91
                os.unlink(dest)
8de3f91
                
8de3f91
            os.symlink(source, dest)
8de3f91
            
8de3f91
        else:
8de3f91
            sys.stderr.write("""
8de3f91
ERROR: the path for dependency "{0}" already exists
8de3f91
8de3f91
This could mean that bundled modules are being installed.  Bundled libraries are
8de3f91
forbidden in Fedora. For more information, see:
8de3f91
    <https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries>
8de3f91
    
8de3f91
It is generally reccomended to remove the entire "node_modules" directory in
8de3f91
%prep when it exists. For more information, see:
8de3f91
    <https://fedoraproject.org/wiki/Packaging:Node.js#Removing_bundled_modules>
8de3f91
    
8de3f91
If you have obtained permission from the Fedora Packaging Committee to bundle
8de3f91
libraries, please use `%nodejs_fixdep -r` in %prep to remove the dependency on
8de3f91
the bundled module. This will prevent an unnecessary dependency on the system
8de3f91
version of the module and eliminate this error.
8de3f91
""".format(dest))
8de3f91
            sys.exit(1)
8de3f91
        
8de3f91
8de3f91
def symlink_deps(deps, check):
8de3f91
    if isinstance(deps, dict):
8de3f91
        #read in the list of mutiple-versioned packages
8de3f91
        mvpkgs = open('/usr/share/node/multiver_modules').read().split('\n')
8de3f91
            
8de3f91
        for dep, ver in deps.items():
8de3f91
            if dep in mvpkgs and ver != '' and ver != '*' and ver != 'latest':
8de3f91
                depver = re.sub('^ *(~|\^|=|>=|<=) *', '', ver).split('.')[0]
8de3f91
                target = os.path.join(sitelib, '{0}@{1}'.format(dep, depver))
8de3f91
            else:
8de3f91
                target = os.path.join(sitelib, dep)
8de3f91
                
8de3f91
            if not check or os.path.exists(target):
8de3f91
                symlink(target, dep)
8de3f91
                
8de3f91
    elif isinstance(deps, list):
8de3f91
        for dep in deps:
8de3f91
            target = os.path.join(sitelib, dep)
8de3f91
            if not check or os.path.exists(target):
8de3f91
                symlink(target, dep)
8de3f91
    
8de3f91
    elif isinstance(deps, str):
8de3f91
        target = os.path.join(sitelib, deps)
8de3f91
        if not check or os.path.exists(target):
8de3f91
            symlink(target, deps)
8de3f91
            
8de3f91
    else:
8de3f91
        raise TypeError("Invalid package.json: dependencies weren't a recognized type")
8de3f91
8de3f91
8de3f91
#the %nodejs_symlink_deps macro passes %nodejs_sitelib as the first argument
8de3f91
sitelib = sys.argv[1]
8de3f91
8de3f91
if '--check' in sys.argv or '--build' in sys.argv:
8de3f91
    check = True
8de3f91
    modules = [os.getcwd()]
8de3f91
else:
8de3f91
    check = False
8de3f91
    br_sitelib = os.path.join(os.environ['RPM_BUILD_ROOT'], sitelib.lstrip('/'))
8de3f91
    modules = [os.path.join(br_sitelib, module) for module in os.listdir(br_sitelib)]
8de3f91
8de3f91
if '--optional' in sys.argv:
8de3f91
    optional = True
8de3f91
else:
8de3f91
    optional = False
8de3f91
8de3f91
for path in modules:
8de3f91
    os.chdir(path)
8de3f91
    md = json.load(open('package.json'))
8de3f91
    
8de3f91
    if 'dependencies' in md or (check and 'devDependencies' in md) or (optional and 'optionalDependencies' in md):
8de3f91
        try:
8de3f91
            os.mkdir('node_modules')
8de3f91
        except OSError:
8de3f91
            sys.stderr.write('WARNING: node_modules already exists. Make sure you have ' +
8de3f91
                                'no bundled dependencies.\n')
8de3f91
8de3f91
        os.chdir('node_modules')
8de3f91
8de3f91
        if 'dependencies' in md:
8de3f91
            symlink_deps(md['dependencies'], check)
8de3f91
8de3f91
        if check and '--no-devdeps' not in sys.argv and 'devDependencies' in md:
8de3f91
            symlink_deps(md['devDependencies'], check)
8de3f91
8de3f91
        if optional and 'optionalDependencies' in md:
8de3f91
            symlink_deps(md['optionalDependencies'], check)