Merged update from upstream sources
This is an automated DistroBaker update from upstream sources. If you do not know what this is about or would like to opt out, contact the OSCI team. Source: https://src.fedoraproject.org/rpms/nodejs-packaging.git#a21e3d16f8963cad3009ad9e99edbbafc5ea327d
This commit is contained in:
parent
e370bc1181
commit
de8e2571e1
35
.gitignore
vendored
35
.gitignore
vendored
@ -1,27 +1,14 @@
|
||||
*~
|
||||
*.swp
|
||||
__pycache__/
|
||||
*.pyc
|
||||
nodejs_req.py
|
||||
test/*/package.json
|
||||
test/*/nodejs.prov.err
|
||||
test/*/nodejs.prov.out
|
||||
test/*/nodejs.req.err
|
||||
test/*/nodejs.req.out
|
||||
*.rpm
|
||||
.build-*.log
|
||||
noarch/
|
||||
nodejs-packaging-fedora-*/
|
||||
/nodejs-packaging-fedora-2.tar.xz
|
||||
/nodejs-packaging-fedora-3.tar.xz
|
||||
/nodejs-packaging-fedora-4.tar.xz
|
||||
/nodejs-packaging-fedora-6.tar.xz
|
||||
/nodejs-packaging-fedora-7.tar.xz
|
||||
/nodejs-packaging-fedora-8.tar.xz
|
||||
/nodejs-packaging-fedora-9.tar.xz
|
||||
/nodejs-packaging-fedora-10.tar.xz
|
||||
/nodejs-packaging-fedora-11.tar.xz
|
||||
/nodejs-packaging-fedora-12.tar.xz
|
||||
/nodejs-packaging-fedora-13.tar.xz
|
||||
/nodejs-packaging-fedora-14.tar.xz
|
||||
/nodejs-packaging-fedora-15.tar.xz
|
||||
/nodejs-packaging-fedora-16.tar.xz
|
||||
/nodejs-packaging-fedora-17.tar.xz
|
||||
/nodejs-packaging-fedora-18.tar.xz
|
||||
/nodejs-packaging-fedora-19.tar.xz
|
||||
/nodejs-packaging-fedora-20.tar.xz
|
||||
/nodejs-packaging-fedora-21.tar.xz
|
||||
/nodejs-packaging-fedora-22.tar.xz
|
||||
/nodejs-packaging-fedora-23.tar.xz
|
||||
/nodejs-packaging-fedora-24.tar.xz
|
||||
/nodejs-packaging-fedora-25.tar.xz
|
||||
/test.tar.gz
|
||||
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright 2012, 2013 T.C. Hollingsworth <tchollingsworth@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
218
README.md
Normal file
218
README.md
Normal file
@ -0,0 +1,218 @@
|
||||
# How to update Node.js in Fedora
|
||||
|
||||
## Determine the Node.js version
|
||||
Monitor the [Node.js Blog](https://nodejs.org/en/blog/) to be notified of
|
||||
available updates.
|
||||
|
||||
For simplicity and copy-and-paste of instructions below, set some variables
|
||||
here:
|
||||
|
||||
```
|
||||
NODEJS_MAJOR=12
|
||||
NODEJS_VERSION=12.9.0
|
||||
```
|
||||
|
||||
## Clone the Fedora package repository
|
||||
These steps assume that you are a comaintainer of Node.js or a provenpackager
|
||||
in Fedora.
|
||||
|
||||
```
|
||||
fedpkg clone nodejs nodejs-fedora
|
||||
```
|
||||
|
||||
Next, switch to the major version branch you are going to update. We'll use
|
||||
Node.js 12.9.0 in this document. Adjust the versions appropriately for the
|
||||
version you are working on.
|
||||
|
||||
```
|
||||
pushd nodejs-fedora
|
||||
fedpkg switch-branch $NODEJS_MAJOR
|
||||
popd
|
||||
```
|
||||
|
||||
|
||||
## Clone the Fedora Module repository
|
||||
|
||||
```
|
||||
fedpkg clone modules/nodejs nodejs-fedora-module
|
||||
```
|
||||
|
||||
|
||||
## Clone the upstream Node.js repository
|
||||
```
|
||||
git clone -o upstream git://github.com/nodejs/node.git nodejs-upstream
|
||||
```
|
||||
|
||||
|
||||
## Rebase the Fedora patches atop the latest release
|
||||
|
||||
```
|
||||
pushd nodejs-upstream
|
||||
git checkout -b fedora-v$NODEJS_VERSION v$NODEJS_VERSION
|
||||
git am -3 ../nodejs-fedora/*.patch
|
||||
```
|
||||
|
||||
If the patches do not apply cleanly, resolve the merges appropriately. Once
|
||||
they have all been applied, output them again:
|
||||
|
||||
```
|
||||
git format-patch -M --patience --full-index -o ../nodejs-fedora v$NODEJS_VERSION..HEAD
|
||||
popd
|
||||
```
|
||||
|
||||
|
||||
## Update the Node.js tarball and specfile
|
||||
|
||||
```
|
||||
pushd nodejs-fedora
|
||||
./nodejs-tarball.sh $NODEJS_VERSION
|
||||
```
|
||||
|
||||
Note that this command will also output all of the versions for the software
|
||||
bundled with Node.js. You will need to edit `nodejs.spec` and update the
|
||||
%global values near the top of that file to include the appropriate values
|
||||
matching the dependencies. Make sure to also update the Node.js versions too!
|
||||
|
||||
Note that if libuv is updated, you need to ensure that the libuv in each
|
||||
buildroot is of a sufficient version. If not, you may need to update that
|
||||
package first and submit a buildroot override.
|
||||
|
||||
Update the RPM spec %changelog appropriately.
|
||||
|
||||
|
||||
## (Preferred) Perform a scratch-build on at least one architecture
|
||||
|
||||
```
|
||||
fedpkg scratch-build [--arches x86_64] --srpm
|
||||
```
|
||||
|
||||
Verify that it built successfully.
|
||||
|
||||
|
||||
## Push the changes up to Fedora
|
||||
```
|
||||
fedpkg commit -cs
|
||||
fedpkg push
|
||||
popd
|
||||
```
|
||||
|
||||
|
||||
## (Optional) Build for Fedora releases
|
||||
|
||||
If this major version is the default for one or more Fedora releases, build it
|
||||
for them. (Note: this step will go away in the future, once module default
|
||||
streams are available in the non-modular buildroot.)
|
||||
|
||||
In the case of Node.js 12.x, this is the default version for Fedora 31 and 32.
|
||||
|
||||
```
|
||||
pushd nodejs-fedora
|
||||
fedpkg switch-branch [master|31]
|
||||
git merge $NODEJS_MAJOR
|
||||
fedpkg push
|
||||
fedpkg build
|
||||
popd
|
||||
```
|
||||
|
||||
## Build module stream
|
||||
|
||||
```
|
||||
pushd nodejs-fedora-module
|
||||
fedpkg switch-branch $NODEJS_MAJOR
|
||||
```
|
||||
|
||||
If the module has changed any package dependencies (such as added a dep on a
|
||||
new shared library), you may need to modify nodejs.yaml here. If not, you can
|
||||
simply run:
|
||||
|
||||
```
|
||||
git commit --allow-empty -sm "Update to $NODEJS_VERSION"
|
||||
fedpkg push
|
||||
fedpkg module-build
|
||||
popd
|
||||
```
|
||||
|
||||
## Submit built packages to Bodhi
|
||||
Follow the usual processes for stable/branched releases to submit builds for
|
||||
testing.
|
||||
|
||||
|
||||
# How to bundle nodejs libraries in Fedora
|
||||
|
||||
The upstream Node.js stance on
|
||||
[global library packages](https://nodejs.org/en/blog/npm/npm-1-0-global-vs-local-installation/)
|
||||
is that they are ".. best avoided if not needed." In Fedora, we take the same
|
||||
stance with our nodejs packages. You can provide a package that uses nodejs,
|
||||
but you should bundle all the nodejs libraries that are needed.
|
||||
|
||||
We are providing a sample spec file and bundling script here.
|
||||
For more detailed packaging information go to the
|
||||
[Fedora Node.js Packaging Guildelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/Node.js/)
|
||||
|
||||
## Bundling Script
|
||||
|
||||
```
|
||||
nodejs-packaging-bundler <npm_name> [version]
|
||||
```
|
||||
|
||||
nodejs-packaging-bundler is it's own package, nodejs-packaging-bundler and must be installed before use.
|
||||
nodejs-packaging-bundler gets the latest npm version available, if no version is given.
|
||||
It produces four files and puts them in ${HOME}/rpmbuild/SOURCES
|
||||
|
||||
* <npm_name>-<version>.tgz - This is the tarball from npm.org
|
||||
* <npm_name>-<version>-nm-prod.tgz - This is the tarball that contains all the bundled nodejs modules <npm_name> needs to run
|
||||
* <npm_name>-<version>-nm-dev.tgz - This is the tarball that contains all the bundled nodejs modules <npm_name> needs to test
|
||||
* <npm_name>-<version>-bundled-licenses.txt - This lists the bundled licenses in <npm_name>-<version>-nm-prod.tgz
|
||||
|
||||
## Sample Spec File
|
||||
|
||||
```
|
||||
%global npm_name my_nodejs_application
|
||||
...
|
||||
License: <license1> and <license2> and <license3>
|
||||
...
|
||||
Source0: http://registry.npmjs.org/%{npm_name}/-/%{npm_name}-%{version}.tgz
|
||||
Source1: %{npm_name}-%{version}-nm-prod.tgz
|
||||
Source2: %{npm_name}-%{version}-nm-dev.tgz
|
||||
Source3: %{npm_name}-%{version}-bundled-licenses.txt
|
||||
...
|
||||
BuildRequires: nodejs-devel
|
||||
...
|
||||
%prep
|
||||
%setup -q -n package
|
||||
cp %{SOURCE3} .
|
||||
...
|
||||
%build
|
||||
# Setup bundled node modules
|
||||
tar xfz %{SOURCE1}
|
||||
mkdir -p node_modules
|
||||
pushd node_modules
|
||||
ln -s ../node_modules_prod/* .
|
||||
ln -s ../node_modules_prod/.bin .
|
||||
popd
|
||||
...
|
||||
%install
|
||||
mkdir -p %{buildroot}%{nodejs_sitelib}/%{npm_name}
|
||||
cp -pr index.js lib package.json %{buildroot}%{nodejs_sitelib}/%{npm_name}
|
||||
# Copy over bundled nodejs modules
|
||||
cp -pr node_modules node_modules_prod %{buildroot}%{nodejs_sitelib}/%{npm_name}
|
||||
...
|
||||
%check
|
||||
%nodejs_symlink_deps --check
|
||||
# Setup bundled dev node_modules for testing
|
||||
tar xfz %{SOURCE2}
|
||||
pushd node_modules
|
||||
ln -s ../node_modules_dev/* .
|
||||
popd
|
||||
pushd node_modules/.bin
|
||||
ln -s ../../node_modules_dev/.bin/* .
|
||||
popd
|
||||
# Example test run using the binary in ./node_modules/.bin/
|
||||
./node_modules/.bin/vows --spec --isolate
|
||||
...
|
||||
%files
|
||||
%doc HISTORY.md
|
||||
%license LICENSE.md %{npm_name}-%{version}-bundled-licenses.txt
|
||||
%{nodejs_sitelib}/%{npm_name}
|
||||
```
|
||||
|
37
macros.nodejs
Normal file
37
macros.nodejs
Normal file
@ -0,0 +1,37 @@
|
||||
# nodejs binary
|
||||
%__nodejs %{_bindir}/node
|
||||
|
||||
# nodejs library directory
|
||||
%nodejs_sitelib %{_prefix}/lib/node_modules
|
||||
|
||||
#arch specific library directory
|
||||
#for future-proofing only; we don't do multilib
|
||||
%nodejs_sitearch %{nodejs_sitelib}
|
||||
|
||||
# currently installed nodejs version
|
||||
%nodejs_version %(%{__nodejs} -v | sed s/v//)
|
||||
|
||||
# symlink dependencies so `npm link` works
|
||||
# this should be run in every module's %%install section
|
||||
# pass --check to work in the current directory instead of the buildroot
|
||||
# pass --no-devdeps to ignore devDependencies when --check is used
|
||||
%nodejs_symlink_deps %{_rpmconfigdir}/nodejs-symlink-deps %{nodejs_sitelib}
|
||||
|
||||
# patch package.json to fix a dependency
|
||||
# see `man npm-json` for details on writing dependencies for package.json files
|
||||
# e.g. `%%nodejs_fixdep frobber` makes any version of frobber do
|
||||
# `%%nodejs_fixdep frobber '>1.0'` requires frobber > 1.0
|
||||
# `%%nodejs_fixdep -r frobber removes the frobber dep
|
||||
%nodejs_fixdep %{_rpmconfigdir}/nodejs-fixdep
|
||||
|
||||
# patch package.json to set the package version
|
||||
# e.g. `%%nodejs_setversion 1.2.3`
|
||||
%nodejs_setversion %{_rpmconfigdir}/nodejs-setversion
|
||||
|
||||
# macro to filter unwanted provides from Node.js binary native modules
|
||||
%nodejs_default_filter %{expand: \
|
||||
%global __provides_exclude_from ^%{nodejs_sitearch}/.*\\.node$
|
||||
}
|
||||
|
||||
# no-op macro to allow spec compatibility with EPEL
|
||||
%nodejs_find_provides_and_requires %{nil}
|
3
multiver_modules
Normal file
3
multiver_modules
Normal file
@ -0,0 +1,3 @@
|
||||
uglify-js
|
||||
inherits
|
||||
nan
|
117
nodejs-fixdep
Executable file
117
nodejs-fixdep
Executable file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
"""Modify a dependency listed in a package.json file"""
|
||||
|
||||
# Copyright 2013 T.C. Hollingsworth <tchollingsworth@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
import json
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
RE_VERSION = re.compile(r'\s*v?([<>=~^]{0,2})\s*([0-9][0-9\.\-]*)\s*')
|
||||
|
||||
p = optparse.OptionParser(
|
||||
description='Modifies dependency entries in package.json files')
|
||||
|
||||
p.add_option('-r', '--remove', action='store_true')
|
||||
p.add_option('-m', '--move', action='store_true')
|
||||
p.add_option('--dev', action='store_const', const='devDependencies',
|
||||
dest='deptype', help='affect devDependencies')
|
||||
p.add_option('--optional', action='store_const', const='optionalDependencies',
|
||||
dest='deptype', help='affect optionalDependencies')
|
||||
p.add_option('--caret', action='store_true',
|
||||
help='convert all or specified dependencies to use the caret operator')
|
||||
|
||||
options, args = p.parse_args()
|
||||
|
||||
if not os.path.exists('package.json~'):
|
||||
shutil.copy2('package.json', 'package.json~')
|
||||
|
||||
md = json.load(open('package.json'))
|
||||
|
||||
deptype = options.deptype if options.deptype is not None else 'dependencies'
|
||||
|
||||
if deptype not in md:
|
||||
md[deptype] = {}
|
||||
|
||||
# convert alternate JSON dependency representations to a dictionary
|
||||
if not options.caret and not isinstance(md[deptype], dict):
|
||||
if isinstance(md[deptype], list):
|
||||
deps = md[deptype]
|
||||
md[deptype] = {}
|
||||
for dep in deps:
|
||||
md[deptype][dep] = '*'
|
||||
elif isinstance(md[deptype], str):
|
||||
md[deptype] = { md[deptype] : '*' }
|
||||
|
||||
if options.remove:
|
||||
dep = args[0]
|
||||
del md[deptype][dep]
|
||||
elif options.move:
|
||||
dep = args[0]
|
||||
ver = None
|
||||
for fromtype in ['dependencies', 'optionalDependencies', 'devDependencies']:
|
||||
if fromtype in md:
|
||||
if isinstance(md[fromtype], dict) and dep in md[fromtype]:
|
||||
ver = md[fromtype][dep]
|
||||
del md[fromtype][dep]
|
||||
elif isinstance(md[fromtype], list) and md[fromtype].count(dep) > 0:
|
||||
ver = '*'
|
||||
md[fromtype].remove(dep)
|
||||
elif isinstance(md[fromtype], str) and md[fromtype] == dep:
|
||||
ver = '*'
|
||||
del md[fromtype]
|
||||
if ver != None:
|
||||
md[deptype][dep] = ver
|
||||
elif options.caret:
|
||||
if not isinstance(md[deptype], dict):
|
||||
sys.stderr.write('All dependencies are unversioned. Unable to apply ' +
|
||||
'caret operator.\n')
|
||||
sys.exit(2)
|
||||
|
||||
deps = args if len(args) > 0 else md[deptype].keys()
|
||||
for dep in deps:
|
||||
if md[deptype][dep][0] == '^':
|
||||
continue
|
||||
elif md[deptype][dep][0] in ('~','0','1','2','3','4','5','6','7','8','9'):
|
||||
ver = re.match(RE_VERSION, md[deptype][dep]).group(2)
|
||||
md[deptype][dep] = '^' + ver
|
||||
else:
|
||||
sys.stderr.write('Attempted to convert non-numeric or tilde ' +
|
||||
'dependency to caret. This is not permitted.\n')
|
||||
sys.exit(1)
|
||||
else:
|
||||
dep = args[0]
|
||||
|
||||
if len(args) > 1:
|
||||
ver = args[1]
|
||||
else:
|
||||
ver = '*'
|
||||
|
||||
md[deptype][dep] = ver
|
||||
|
||||
fh = open('package.json', 'w')
|
||||
data = json.JSONEncoder(indent=4).encode(md)
|
||||
fh.write(data)
|
||||
fh.close()
|
84
nodejs-packaging-bundler
Executable file
84
nodejs-packaging-bundler
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
OUTPUT_DIR="${HOME}/rpmbuild/SOURCES"
|
||||
|
||||
usage() {
|
||||
echo "Usage `basename $0` <npm_name> [version] " >&2
|
||||
echo >&2
|
||||
echo " Given a npm module name, and optionally a version," >&2
|
||||
echo " download the npm, the prod and dev dependencies," >&2
|
||||
echo " each in their own tarball." >&2
|
||||
echo " Also finds licenses prod dependencies." >&2
|
||||
echo " All three tarballs and license list are copied to ${OUTPUT_DIR}" >&2
|
||||
echo >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ! [ -f /usr/bin/npm ]; then
|
||||
echo >&2
|
||||
echo "`basename $0` requires npm to run" >&2
|
||||
echo >&2
|
||||
echo "Run the following to fix this" >&2
|
||||
echo " sudo dnf install npm" >&2
|
||||
echo >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
usage
|
||||
else
|
||||
case $1 in
|
||||
-h | --help )
|
||||
usage
|
||||
;;
|
||||
* )
|
||||
PACKAGE="$1"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ $# -ge 2 ]; then
|
||||
VERSION="$2"
|
||||
else
|
||||
VERSION="$(npm view ${PACKAGE} version)"
|
||||
fi
|
||||
# the package name might contain invalid characters, sanitize first
|
||||
PACKAGE_SAFE=$(echo $PACKAGE | sed -e 's|/|-|g')
|
||||
TMP_DIR=$(mktemp -d -t ci-XXXXXXXXXX)
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
mkdir -p ${TMP_DIR}
|
||||
pushd ${TMP_DIR}
|
||||
npm pack ${PACKAGE}
|
||||
tar xfz *.tgz
|
||||
cd package
|
||||
echo " Downloading prod dependencies"
|
||||
npm install --no-optional --only=prod
|
||||
if [ $? -ge 1 ] ; then
|
||||
echo " ERROR WILL ROBINSON"
|
||||
rm -rf node_modules
|
||||
else
|
||||
echo " Successful prod dependences download"
|
||||
mv node_modules/ node_modules_prod
|
||||
fi
|
||||
echo "LICENSES IN BUNDLE:"
|
||||
find . -name "package.json" -exec jq .license {} \; >> ${TMP_DIR}/${PACKAGE_SAFE}-${VERSION}-bundled-licenses.txt
|
||||
find . -name "package.json" -exec jq '.licenses[] .type' {} \; >> ${TMP_DIR}/${PACKAGE_SAFE}-${VERSION}-bundled-licenses.txt 2>/dev/null
|
||||
sed -i "/^null$/d" ${TMP_DIR}/${PACKAGE_SAFE}-${VERSION}-bundled-licenses.txt
|
||||
sort -u -o ${TMP_DIR}/${PACKAGE_SAFE}-${VERSION}-bundled-licenses.txt ${TMP_DIR}/${PACKAGE_SAFE}-${VERSION}-bundled-licenses.txt
|
||||
echo " Downloading dev dependencies"
|
||||
npm install --no-optional --only=dev
|
||||
if [ $? -ge 1 ] ; then
|
||||
echo " ERROR WILL ROBINSON"
|
||||
else
|
||||
echo " Successful dev dependences download"
|
||||
mv node_modules/ node_modules_dev
|
||||
fi
|
||||
if [ -d node_modules_prod ] ; then
|
||||
tar cfz ../${PACKAGE_SAFE}-${VERSION}-nm-prod.tgz node_modules_prod
|
||||
fi
|
||||
if [ -d node_modules_dev ] ; then
|
||||
tar cfz ../${PACKAGE_SAFE}-${VERSION}-nm-dev.tgz node_modules_dev
|
||||
fi
|
||||
cd ..
|
||||
cp -v ${PACKAGE_SAFE}-${VERSION}* $HOME/rpmbuild/SOURCES
|
||||
popd > /dev/null
|
||||
rm -rf ${TMP_DIR}
|
@ -1,15 +1,29 @@
|
||||
%global macrosdir %(d=%{_rpmconfigdir}/macros.d; [ -d $d ] || d=%{_sysconfdir}/rpm; echo $d)
|
||||
|
||||
Name: nodejs-packaging
|
||||
Version: 25
|
||||
Release: 1%{?dist}
|
||||
Version: 2021.01
|
||||
Release: 2%{?dist}
|
||||
Summary: RPM Macros and Utilities for Node.js Packaging
|
||||
BuildArch: noarch
|
||||
License: MIT
|
||||
URL: https://fedoraproject.org/wiki/Node.js/Packagers
|
||||
Source0: https://releases.pagure.org/%{name}/%{name}-fedora-%{version}.tar.xz
|
||||
ExclusiveArch: %{nodejs_arches} noarch
|
||||
|
||||
Source0001: LICENSE
|
||||
Source0002: README.md
|
||||
Source0003: macros.nodejs
|
||||
Source0004: multiver_modules
|
||||
Source0005: nodejs-fixdep
|
||||
Source0006: nodejs-setversion
|
||||
Source0007: nodejs-symlink-deps
|
||||
Source0008: nodejs.attr
|
||||
Source0009: nodejs.prov
|
||||
Source0010: nodejs.req
|
||||
Source0011: nodejs-packaging-bundler
|
||||
|
||||
# Created with `tar cfz test.tar.gz test`
|
||||
Source0101: test.tar.gz
|
||||
|
||||
BuildRequires: python3
|
||||
|
||||
Requires: redhat-rpm-config
|
||||
@ -18,9 +32,23 @@ Requires: redhat-rpm-config
|
||||
This package contains RPM macros and other utilities useful for packaging
|
||||
Node.js modules and applications in RPM-based distributions.
|
||||
|
||||
%package bundler
|
||||
Summary: Bundle a node.js application dependencies
|
||||
Requires: npm
|
||||
Requires: coreutils, findutils, jq
|
||||
|
||||
%description bundler
|
||||
nodejs-packaging-bundler bundles a node.js application node_module dependencies
|
||||
It gathers the application tarball.
|
||||
It generates a runtime (prod) tarball with runtime node_module dependencies
|
||||
It generates a testing (dev) tarball with node_module dependencies for testing
|
||||
It generates a bundled licence file that gets the licenses in the runtime dependency tarball
|
||||
|
||||
%prep
|
||||
%autosetup -p 1 -n %{name}-fedora-%{version}
|
||||
pushd %{_topdir}/BUILD
|
||||
cp -da %{_sourcedir}/* .
|
||||
tar xvf test.tar.gz
|
||||
popd
|
||||
|
||||
|
||||
%build
|
||||
@ -36,6 +64,7 @@ install -pm0755 nodejs-symlink-deps %{buildroot}%{_rpmconfigdir}/nodejs-symlink-
|
||||
install -pm0755 nodejs-fixdep %{buildroot}%{_rpmconfigdir}/nodejs-fixdep
|
||||
install -pm0755 nodejs-setversion %{buildroot}%{_rpmconfigdir}/nodejs-setversion
|
||||
install -Dpm0644 multiver_modules %{buildroot}%{_datadir}/node/multiver_modules
|
||||
install -Dpm0755 nodejs-packaging-bundler %{buildroot}%{_bindir}/nodejs-packaging-bundler
|
||||
|
||||
|
||||
%check
|
||||
@ -49,8 +78,20 @@ install -Dpm0644 multiver_modules %{buildroot}%{_datadir}/node/multiver_modules
|
||||
%{_rpmconfigdir}/nodejs*
|
||||
%{_datadir}/node/multiver_modules
|
||||
|
||||
%files bundler
|
||||
%{_bindir}/nodejs-packaging-bundler
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Jan 20 2021 Stephen Gallagher <sgallagh@redhat.com> - 2021.01-2
|
||||
- nodejs-packaging-bundler improvements to handle uncommon characters
|
||||
|
||||
* Wed Jan 06 2021 Troy Dawson <tdawson@redhat.com> - 2021.01
|
||||
- Add nodejs-packaging-bundler and update README.md
|
||||
|
||||
* Fri Sep 18 2020 Stephen Gallagher <sgallagh@redhat.com> - 2020.09-1
|
||||
- Move to dist-git as the upstream
|
||||
|
||||
* Wed Sep 02 2020 Stephen Gallagher <sgallagh@redhat.com> - 25-1
|
||||
- Fix incorrect bundled library detection for Requires
|
||||
|
||||
|
43
nodejs-setversion
Executable file
43
nodejs-setversion
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
"""Set a package version in a package.json file"""
|
||||
|
||||
# Copyright 2018 Tom Hughes <tom@compton.nu>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
if not os.path.exists('package.json~'):
|
||||
shutil.copy2('package.json', 'package.json~')
|
||||
|
||||
md = json.load(open('package.json'))
|
||||
|
||||
if 'version' in md and sys.argv[1] != md['version']:
|
||||
raise RuntimeError('Version is already set to {0}'.format(md['version']))
|
||||
else:
|
||||
md['version'] = sys.argv[1]
|
||||
|
||||
fh = open('package.json', 'w')
|
||||
data = json.JSONEncoder(indent=4).encode(md)
|
||||
fh.write(data)
|
||||
fh.close()
|
141
nodejs-symlink-deps
Executable file
141
nodejs-symlink-deps
Executable file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
"""Symlink a node module's dependencies into the node_modules directory so users
|
||||
can `npm link` RPM-installed modules into their personal projects."""
|
||||
|
||||
# Copyright 2012, 2013 T.C. Hollingsworth <tchollingsworth@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
def symlink(source, dest):
|
||||
try:
|
||||
os.symlink(source, dest)
|
||||
except OSError:
|
||||
if os.path.islink(dest) and os.path.realpath(dest) == os.path.normpath(source):
|
||||
sys.stderr.write("""
|
||||
WARNING: the symlink for dependency "{0}" already exists
|
||||
|
||||
This could mean that the dependency exists in both devDependencies and
|
||||
dependencies, which may cause trouble for people using this module with npm.
|
||||
|
||||
Please report this to upstream. For more information, see:
|
||||
<https://github.com/tchollingsworth/nodejs-packaging/pull/1>
|
||||
""".format(dest))
|
||||
|
||||
elif '--force' in sys.argv:
|
||||
if os.path.isdir(dest):
|
||||
shutil.rmtree(dest)
|
||||
else:
|
||||
os.unlink(dest)
|
||||
|
||||
os.symlink(source, dest)
|
||||
|
||||
else:
|
||||
sys.stderr.write("""
|
||||
ERROR: the path for dependency "{0}" already exists
|
||||
|
||||
This could mean that bundled modules are being installed. Bundled libraries are
|
||||
forbidden in Fedora. For more information, see:
|
||||
<https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries>
|
||||
|
||||
It is generally reccomended to remove the entire "node_modules" directory in
|
||||
%prep when it exists. For more information, see:
|
||||
<https://fedoraproject.org/wiki/Packaging:Node.js#Removing_bundled_modules>
|
||||
|
||||
If you have obtained permission from the Fedora Packaging Committee to bundle
|
||||
libraries, please use `%nodejs_fixdep -r` in %prep to remove the dependency on
|
||||
the bundled module. This will prevent an unnecessary dependency on the system
|
||||
version of the module and eliminate this error.
|
||||
""".format(dest))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def symlink_deps(deps, check):
|
||||
if isinstance(deps, dict):
|
||||
#read in the list of mutiple-versioned packages
|
||||
mvpkgs = open('/usr/share/node/multiver_modules').read().split('\n')
|
||||
|
||||
for dep, ver in deps.items():
|
||||
if dep in mvpkgs and ver != '' and ver != '*' and ver != 'latest':
|
||||
depver = re.sub('^ *(~|\^|=|>=|<=) *', '', ver).split('.')[0]
|
||||
target = os.path.join(sitelib, '{0}@{1}'.format(dep, depver))
|
||||
else:
|
||||
target = os.path.join(sitelib, dep)
|
||||
|
||||
if not check or os.path.exists(target):
|
||||
symlink(target, dep)
|
||||
|
||||
elif isinstance(deps, list):
|
||||
for dep in deps:
|
||||
target = os.path.join(sitelib, dep)
|
||||
if not check or os.path.exists(target):
|
||||
symlink(target, dep)
|
||||
|
||||
elif isinstance(deps, str):
|
||||
target = os.path.join(sitelib, deps)
|
||||
if not check or os.path.exists(target):
|
||||
symlink(target, deps)
|
||||
|
||||
else:
|
||||
raise TypeError("Invalid package.json: dependencies weren't a recognized type")
|
||||
|
||||
|
||||
#the %nodejs_symlink_deps macro passes %nodejs_sitelib as the first argument
|
||||
sitelib = sys.argv[1]
|
||||
|
||||
if '--check' in sys.argv or '--build' in sys.argv:
|
||||
check = True
|
||||
modules = [os.getcwd()]
|
||||
else:
|
||||
check = False
|
||||
br_sitelib = os.path.join(os.environ['RPM_BUILD_ROOT'], sitelib.lstrip('/'))
|
||||
modules = [os.path.join(br_sitelib, module) for module in os.listdir(br_sitelib)]
|
||||
|
||||
if '--optional' in sys.argv:
|
||||
optional = True
|
||||
else:
|
||||
optional = False
|
||||
|
||||
for path in modules:
|
||||
os.chdir(path)
|
||||
md = json.load(open('package.json'))
|
||||
|
||||
if 'dependencies' in md or (check and 'devDependencies' in md) or (optional and 'optionalDependencies' in md):
|
||||
try:
|
||||
os.mkdir('node_modules')
|
||||
except OSError:
|
||||
sys.stderr.write('WARNING: node_modules already exists. Make sure you have ' +
|
||||
'no bundled dependencies.\n')
|
||||
|
||||
os.chdir('node_modules')
|
||||
|
||||
if 'dependencies' in md:
|
||||
symlink_deps(md['dependencies'], check)
|
||||
|
||||
if check and '--no-devdeps' not in sys.argv and 'devDependencies' in md:
|
||||
symlink_deps(md['devDependencies'], check)
|
||||
|
||||
if optional and 'optionalDependencies' in md:
|
||||
symlink_deps(md['optionalDependencies'], check)
|
4
nodejs.attr
Normal file
4
nodejs.attr
Normal file
@ -0,0 +1,4 @@
|
||||
%__nodejs_provides %{_rpmconfigdir}/nodejs.prov
|
||||
%__nodejs_requires %{_rpmconfigdir}/nodejs.req
|
||||
%__nodejs_suggests %{_rpmconfigdir}/nodejs.req --optional
|
||||
%__nodejs_path ^/usr/lib(64)?/node_modules/[^/]+/package\\.json$
|
121
nodejs.prov
Executable file
121
nodejs.prov
Executable file
@ -0,0 +1,121 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2012 T.C. Hollingsworth <tchollingsworth@gmail.com>
|
||||
# Copyright 2017 Tomas Tomecek <ttomecek@redhat.com>
|
||||
# Copyright 2019 Jan Staněk <jstanek@redhat.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
"""Automatic provides generator for Node.js libraries.
|
||||
|
||||
Metadata taken from package.json. See `man npm-json` for details.
|
||||
"""
|
||||
|
||||
from __future__ import print_function, with_statement
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from itertools import chain, groupby
|
||||
|
||||
DEPENDENCY_TEMPLATE = "npm(%(name)s) = %(version)s"
|
||||
BUNDLED_TEMPLATE = "bundled(nodejs-%(name)s) = %(version)s"
|
||||
NODE_MODULES = {"node_modules", "node_modules_prod"}
|
||||
|
||||
|
||||
class PrivatePackage(RuntimeError):
|
||||
"""Private package metadata that should not be listed."""
|
||||
|
||||
|
||||
#: Something is wrong with the ``package.json`` file
|
||||
_INVALID_METADATA_FILE = (IOError, PrivatePackage, KeyError)
|
||||
|
||||
|
||||
def format_metadata(metadata, bundled=False):
|
||||
"""Format ``package.json``-like metadata into RPM dependency.
|
||||
|
||||
Arguments:
|
||||
metadata (dict): Package metadata, presumably read from ``package.json``.
|
||||
bundled (bool): Should the bundled dependency format be used?
|
||||
|
||||
Returns:
|
||||
str: RPM dependency (i.e. ``npm(example) = 1.0.0``)
|
||||
|
||||
Raises:
|
||||
KeyError: Expected key (i.e. ``name``, ``version``) missing in metadata.
|
||||
PrivatePackage: The metadata indicate private (unlisted) package.
|
||||
"""
|
||||
|
||||
# Skip private packages
|
||||
if metadata.get("private", False):
|
||||
raise PrivatePackage(metadata)
|
||||
|
||||
template = BUNDLED_TEMPLATE if bundled else DEPENDENCY_TEMPLATE
|
||||
return template % metadata
|
||||
|
||||
|
||||
def generate_dependencies(module_path, module_dir_set=NODE_MODULES):
|
||||
"""Generate RPM dependency for a module and all it's dependencies.
|
||||
|
||||
Arguments:
|
||||
module_path (str): Path to a module directory or it's ``package.json``
|
||||
module_dir_set (set): Base names of directories to look into
|
||||
for bundled dependencies.
|
||||
|
||||
Yields:
|
||||
str: RPM dependency for the module and each of it's (public) bundled dependencies.
|
||||
|
||||
Raises:
|
||||
ValueError: module_path is not valid module or ``package.json`` file
|
||||
"""
|
||||
|
||||
# Determine paths to root module directory and package.json
|
||||
if os.path.isdir(module_path):
|
||||
root_dir = module_path
|
||||
elif os.path.basename(module_path) == "package.json":
|
||||
root_dir = os.path.dirname(module_path)
|
||||
else: # Invalid metadata path
|
||||
raise ValueError("Invalid module path '%s'" % module_path)
|
||||
|
||||
for dir_path, subdir_list, __ in os.walk(root_dir):
|
||||
# Currently in node_modules (or similar), continue to subdirs
|
||||
if os.path.basename(dir_path) in module_dir_set:
|
||||
continue
|
||||
|
||||
# Read and format metadata
|
||||
metadata_path = os.path.join(dir_path, "package.json")
|
||||
bundled = dir_path != root_dir
|
||||
try:
|
||||
with open(metadata_path, mode="r") as metadata_file:
|
||||
metadata = json.load(metadata_file)
|
||||
yield format_metadata(metadata, bundled=bundled)
|
||||
except _INVALID_METADATA_FILE:
|
||||
pass # Ignore
|
||||
|
||||
# Only visit subdirectories in module_dir_set
|
||||
subdir_list[:] = list(module_dir_set & set(subdir_list))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
module_paths = (path.strip() for path in sys.stdin)
|
||||
provides = chain.from_iterable(generate_dependencies(m) for m in module_paths)
|
||||
|
||||
# sort|uniq
|
||||
for provide, __ in groupby(sorted(provides)):
|
||||
print(provide)
|
707
nodejs.req
Executable file
707
nodejs.req
Executable file
@ -0,0 +1,707 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2012, 2013 T.C. Hollingsworth <tchollingsworth@gmail.com>
|
||||
# Copyright 2019 Jan Staněk <jstanek@redat.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
""" Automatic dependency generator for Node.js libraries.
|
||||
|
||||
Metadata parsed from package.json. See `man npm-json` for details.
|
||||
"""
|
||||
|
||||
from __future__ import print_function, with_statement
|
||||
|
||||
import json
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from itertools import chain
|
||||
from itertools import takewhile
|
||||
|
||||
# Python version detection
|
||||
_PY2 = sys.version_info[0] <= 2
|
||||
_PY3 = sys.version_info[0] >= 3
|
||||
|
||||
if _PY2:
|
||||
from future_builtins import map, filter
|
||||
|
||||
|
||||
#: Name format of the requirements
|
||||
REQUIREMENT_NAME_TEMPLATE = "npm({name})"
|
||||
|
||||
#: ``simple`` product of the NPM semver grammar.
|
||||
RANGE_SPECIFIER_SIMPLE = re.compile(
|
||||
r"""
|
||||
(?P<operator>
|
||||
<= | >= | < | > | = # primitive
|
||||
| ~ | \^ # tilde/caret operators
|
||||
)?
|
||||
\s*(?P<version>\S+)\s* # version specifier
|
||||
""",
|
||||
flags=re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
class UnsupportedVersionToken(ValueError):
|
||||
"""Version specifier contains token unsupported by the parser."""
|
||||
|
||||
|
||||
class Version(tuple):
|
||||
"""Normalized RPM/NPM version.
|
||||
|
||||
The version has up to 3 components – major, minor, patch.
|
||||
Any part set to None is treated as unspecified.
|
||||
|
||||
::
|
||||
|
||||
1.2.3 == Version(1, 2, 3)
|
||||
1.2 == Version(1, 2)
|
||||
1 == Version(1)
|
||||
* == Version()
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
#: Version part meaning 'Any'
|
||||
#: ``xr`` in https://docs.npmjs.com/misc/semver#range-grammar
|
||||
_PART_ANY = re.compile(r"^[xX*]$")
|
||||
#: Numeric version part
|
||||
#: ``nr`` in https://docs.npmjs.com/misc/semver#range-grammar
|
||||
_PART_NUMERIC = re.compile(r"0|[1-9]\d*")
|
||||
|
||||
def __new__(cls, *args):
|
||||
"""Create new version.
|
||||
|
||||
Arguments:
|
||||
Version components in the order of "major", "minor", "patch".
|
||||
All parts are optional::
|
||||
|
||||
>>> Version(1, 2, 3)
|
||||
Version(1, 2, 3)
|
||||
>>> Version(1)
|
||||
Version(1)
|
||||
>>> Version()
|
||||
Version()
|
||||
|
||||
Returns:
|
||||
New Version.
|
||||
"""
|
||||
|
||||
if len(args) > 3:
|
||||
raise ValueError("Version has maximum of 3 components")
|
||||
return super(Version, cls).__new__(cls, map(int, args))
|
||||
|
||||
def __repr__(self):
|
||||
"""Pretty debugging format."""
|
||||
|
||||
return "{0}({1})".format(self.__class__.__name__, ", ".join(map(str, self)))
|
||||
|
||||
def __str__(self):
|
||||
"""RPM version format."""
|
||||
|
||||
return ".".join(format(part, "d") for part in self)
|
||||
|
||||
@property
|
||||
def major(self):
|
||||
"""Major version number, if any."""
|
||||
return self[0] if len(self) > 0 else None
|
||||
|
||||
@property
|
||||
def minor(self):
|
||||
"""Major version number, if any."""
|
||||
return self[1] if len(self) > 1 else None
|
||||
|
||||
@property
|
||||
def patch(self):
|
||||
"""Major version number, if any."""
|
||||
return self[2] if len(self) > 2 else None
|
||||
|
||||
@property
|
||||
def empty(self):
|
||||
"""True if the version contains nothing but zeroes."""
|
||||
return not any(self)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, version_string):
|
||||
"""Parse individual version string (like ``1.2.3``) into Version.
|
||||
|
||||
This is the ``partial`` production in the grammar:
|
||||
https://docs.npmjs.com/misc/semver#range-grammar
|
||||
|
||||
Examples::
|
||||
|
||||
>>> Version.parse("1.2.3")
|
||||
Version(1, 2, 3)
|
||||
>>> Version.parse("v2.x")
|
||||
Version(2)
|
||||
>>> Version.parse("")
|
||||
Version()
|
||||
|
||||
Arguments:
|
||||
version_string (str): The version_string to parse.
|
||||
|
||||
Returns:
|
||||
Version: Parsed result.
|
||||
"""
|
||||
|
||||
# Ignore leading ``v``, if any
|
||||
version_string = version_string.lstrip("v")
|
||||
|
||||
part_list = version_string.split(".", 2)
|
||||
# Use only parts up to first "Any" indicator
|
||||
part_list = list(takewhile(lambda p: not cls._PART_ANY.match(p), part_list))
|
||||
|
||||
if not part_list:
|
||||
return cls()
|
||||
|
||||
# Strip off and discard any pre-release or build qualifiers at the end.
|
||||
# We can get away with this, because there is no sane way to represent
|
||||
# these kinds of version requirements in RPM, and we generally expect
|
||||
# the distro will only carry proper releases anyway.
|
||||
try:
|
||||
part_list[-1] = cls._PART_NUMERIC.match(part_list[-1]).group()
|
||||
except AttributeError: # no match
|
||||
part_list.pop()
|
||||
|
||||
# Extend with ``None``s at the end, if necessary
|
||||
return cls(*part_list)
|
||||
|
||||
def incremented(self):
|
||||
"""Increment the least significant part of the version::
|
||||
|
||||
>>> Version(1, 2, 3).incremented()
|
||||
Version(1, 2, 4)
|
||||
>>> Version(1, 2).incremented()
|
||||
Version(1, 3)
|
||||
>>> Version(1).incremented()
|
||||
Version(2)
|
||||
>>> Version().incremented()
|
||||
Version()
|
||||
|
||||
Returns:
|
||||
Version: New incremented Version.
|
||||
"""
|
||||
|
||||
if len(self) == 0:
|
||||
return self.__class__()
|
||||
else:
|
||||
args = self[:-1] + (self[-1] + 1,)
|
||||
return self.__class__(*args)
|
||||
|
||||
|
||||
class VersionBoundary(namedtuple("VersionBoundary", ("version", "operator"))):
|
||||
"""Normalized version range boundary."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
#: Ordering of primitive operators.
|
||||
#: Operators not listed here are handled specially; see __compare below.
|
||||
#: Convention: Lower boundary < 0, Upper boundary > 0
|
||||
_OPERATOR_ORDER = {"<": 2, "<=": 1, ">=": -1, ">": -2}
|
||||
|
||||
def __str__(self):
|
||||
"""Pretty-print the boundary"""
|
||||
|
||||
return "{0.operator}{0.version}".format(self)
|
||||
|
||||
def __compare(self, other, operator):
|
||||
"""Compare two boundaries with provided operator.
|
||||
|
||||
Boundaries compare same as (version, operator_order) tuple.
|
||||
In case the boundary operator is not listed in _OPERATOR_ORDER,
|
||||
it's order is treated as 0.
|
||||
|
||||
Arguments:
|
||||
other (VersionBoundary): The other boundary to compare with.
|
||||
operator (Callable[[VersionBoundary, VersionBoundary], bool]):
|
||||
Comparison operator to delegate to.
|
||||
|
||||
Returns:
|
||||
bool: The result of the operator's comparison.
|
||||
"""
|
||||
|
||||
ORDER = self._OPERATOR_ORDER
|
||||
|
||||
lhs = self.version, ORDER.get(self.operator, 0)
|
||||
rhs = other.version, ORDER.get(other.operator, 0)
|
||||
return operator(lhs, rhs)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__compare(other, operator.eq)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.__compare(other, operator.lt)
|
||||
|
||||
def __le__(self, other):
|
||||
return self.__compare(other, operator.le)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.__compare(other, operator.gt)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.__compare(other, operator.ge)
|
||||
|
||||
@property
|
||||
def upper(self):
|
||||
"""True if self is upper boundary."""
|
||||
return self._OPERATOR_ORDER.get(self.operator, 0) > 0
|
||||
|
||||
@property
|
||||
def lower(self):
|
||||
"""True if self is lower boundary."""
|
||||
return self._OPERATOR_ORDER.get(self.operator, 0) < 0
|
||||
|
||||
@classmethod
|
||||
def equal(cls, version):
|
||||
"""Normalize single samp:`={version}` into equivalent x-range::
|
||||
|
||||
>>> empty = VersionBoundary.equal(Version()); tuple(map(str, empty))
|
||||
()
|
||||
>>> patch = VersionBoundary.equal(Version(1, 2, 3)); tuple(map(str, patch))
|
||||
('>=1.2.3', '<1.2.4')
|
||||
>>> minor = VersionBoundary.equal(Version(1, 2)); tuple(map(str, minor))
|
||||
('>=1.2', '<1.3')
|
||||
>>> major = VersionBoundary.equal(Version(1)); tuple(map(str, major))
|
||||
('>=1', '<2')
|
||||
|
||||
See `X-Ranges <https://docs.npmjs.com/misc/semver#x-ranges-12x-1x-12->`_
|
||||
for details.
|
||||
|
||||
Arguments:
|
||||
version (Version): The version the x-range should be equal to.
|
||||
|
||||
Returns:
|
||||
(VersionBoundary, VersionBoundary):
|
||||
Lower and upper bound of the x-range.
|
||||
(): Empty tuple in case version is empty (any version matches).
|
||||
"""
|
||||
|
||||
if version:
|
||||
return (
|
||||
cls(version=version, operator=">="),
|
||||
cls(version=version.incremented(), operator="<"),
|
||||
)
|
||||
else:
|
||||
return ()
|
||||
|
||||
@classmethod
|
||||
def tilde(cls, version):
|
||||
"""Normalize :samp:`~{version}` into equivalent range.
|
||||
|
||||
Tilde allows patch-level changes if a minor version is specified.
|
||||
Allows minor-level changes if not::
|
||||
|
||||
>>> with_minor = VersionBoundary.tilde(Version(1, 2, 3)); tuple(map(str, with_minor))
|
||||
('>=1.2.3', '<1.3')
|
||||
>>> no_minor = VersionBoundary.tilde(Version(1)); tuple(map(str, no_minor))
|
||||
('>=1', '<2')
|
||||
|
||||
Arguments:
|
||||
version (Version): The version to tilde-expand.
|
||||
|
||||
Returns:
|
||||
(VersionBoundary, VersionBoundary):
|
||||
The lower and upper boundary of the tilde range.
|
||||
"""
|
||||
|
||||
# Fail on ``~*`` or similar nonsense specifier
|
||||
assert version.major is not None, "Nonsense '~*' specifier"
|
||||
|
||||
lower_boundary = cls(version=version, operator=">=")
|
||||
|
||||
if version.minor is None:
|
||||
upper_boundary = cls(version=Version(version.major + 1), operator="<")
|
||||
else:
|
||||
upper_boundary = cls(
|
||||
version=Version(version.major, version.minor + 1), operator="<"
|
||||
)
|
||||
|
||||
return lower_boundary, upper_boundary
|
||||
|
||||
@classmethod
|
||||
def caret(cls, version):
|
||||
"""Normalize :samp:`^{version}` into equivalent range.
|
||||
|
||||
Caret allows changes that do not modify the left-most non-zero digit
|
||||
in the ``(major, minor, patch)`` tuple.
|
||||
In other words, this allows
|
||||
patch and minor updates for versions 1.0.0 and above,
|
||||
patch updates for versions 0.X >=0.1.0,
|
||||
and no updates for versions 0.0.X::
|
||||
|
||||
>>> major = VersionBoundary.caret(Version(1, 2, 3)); tuple(map(str, major))
|
||||
('>=1.2.3', '<2')
|
||||
>>> minor = VersionBoundary.caret(Version(0, 2, 3)); tuple(map(str, minor))
|
||||
('>=0.2.3', '<0.3')
|
||||
>>> patch = VersionBoundary.caret(Version(0, 0, 3)); tuple(map(str, patch))
|
||||
('>=0.0.3', '<0.0.4')
|
||||
|
||||
When parsing caret ranges, a missing patch value desugars to the number 0,
|
||||
but will allow flexibility within that value,
|
||||
even if the major and minor versions are both 0::
|
||||
|
||||
>>> rel = VersionBoundary.caret(Version(1, 2)); tuple(map(str, rel))
|
||||
('>=1.2', '<2')
|
||||
>>> pre = VersionBoundary.caret(Version(0, 0)); tuple(map(str, pre))
|
||||
('>=0.0', '<0.1')
|
||||
|
||||
A missing minor and patch values will desugar to zero,
|
||||
but also allow flexibility within those values,
|
||||
even if the major version is zero::
|
||||
|
||||
>>> rel = VersionBoundary.caret(Version(1)); tuple(map(str, rel))
|
||||
('>=1', '<2')
|
||||
>>> pre = VersionBoundary.caret(Version(0)); tuple(map(str, pre))
|
||||
('>=0', '<1')
|
||||
|
||||
Arguments:
|
||||
version (Version): The version to range-expand.
|
||||
|
||||
Returns:
|
||||
(VersionBoundary, VersionBoundary):
|
||||
The lower and upper boundary of caret-range.
|
||||
"""
|
||||
|
||||
# Fail on ^* or similar nonsense specifier
|
||||
assert len(version) != 0, "Nonsense '^*' specifier"
|
||||
|
||||
lower_boundary = cls(version=version, operator=">=")
|
||||
|
||||
# Increment left-most non-zero part
|
||||
for idx, part in enumerate(version):
|
||||
if part != 0:
|
||||
upper_version = Version(*(version[:idx] + (part + 1,)))
|
||||
break
|
||||
else: # No non-zero found; increment last specified part
|
||||
upper_version = version.incremented()
|
||||
|
||||
upper_boundary = cls(version=upper_version, operator="<")
|
||||
|
||||
return lower_boundary, upper_boundary
|
||||
|
||||
@classmethod
|
||||
def hyphen(cls, lower_version, upper_version):
|
||||
"""Construct hyphen range (inclusive set)::
|
||||
|
||||
>>> full = VersionBoundary.hyphen(Version(1, 2, 3), Version(2, 3, 4)); tuple(map(str, full))
|
||||
('>=1.2.3', '<=2.3.4')
|
||||
|
||||
If a partial version is provided as the first version in the inclusive range,
|
||||
then the missing pieces are treated as zeroes::
|
||||
|
||||
>>> part = VersionBoundary.hyphen(Version(1, 2), Version(2, 3, 4)); tuple(map(str, part))
|
||||
('>=1.2', '<=2.3.4')
|
||||
|
||||
If a partial version is provided as the second version in the inclusive range,
|
||||
then all versions that start with the supplied parts of the tuple are accepted,
|
||||
but nothing that would be greater than the provided tuple parts::
|
||||
|
||||
>>> part = VersionBoundary.hyphen(Version(1, 2, 3), Version(2, 3)); tuple(map(str, part))
|
||||
('>=1.2.3', '<2.4')
|
||||
>>> part = VersionBoundary.hyphen(Version(1, 2, 3), Version(2)); tuple(map(str, part))
|
||||
('>=1.2.3', '<3')
|
||||
|
||||
Arguments:
|
||||
lower_version (Version): Version on the lower range boundary.
|
||||
upper_version (Version): Version on the upper range boundary.
|
||||
|
||||
Returns:
|
||||
(VersionBoundary, VersionBoundary):
|
||||
Lower and upper boundaries of the hyphen range.
|
||||
"""
|
||||
|
||||
lower_boundary = cls(version=lower_version, operator=">=")
|
||||
|
||||
if len(upper_version) < 3:
|
||||
upper_boundary = cls(version=upper_version.incremented(), operator="<")
|
||||
else:
|
||||
upper_boundary = cls(version=upper_version, operator="<=")
|
||||
|
||||
return lower_boundary, upper_boundary
|
||||
|
||||
|
||||
def parse_simple_seq(specifier_string):
|
||||
"""Parse all specifiers from a space-separated string::
|
||||
|
||||
>>> single = parse_simple_seq(">=1.2.3"); list(map(str, single))
|
||||
['>=1.2.3']
|
||||
>>> multi = parse_simple_seq("~1.2.0 <1.2.5"); list(map(str, multi))
|
||||
['>=1.2.0', '<1.3', '<1.2.5']
|
||||
|
||||
This method implements the ``simple (' ' simple)*`` part of the grammar:
|
||||
https://docs.npmjs.com/misc/semver#range-grammar.
|
||||
|
||||
Arguments:
|
||||
specifier_string (str): Space-separated string of simple version specifiers.
|
||||
|
||||
Yields:
|
||||
VersionBoundary: Parsed boundaries.
|
||||
"""
|
||||
|
||||
# Per-operator dispatch table
|
||||
# API: Callable[[Version], Iterable[VersionBoundary]]
|
||||
handler = {
|
||||
">": lambda v: [VersionBoundary(version=v, operator=">")],
|
||||
">=": lambda v: [VersionBoundary(version=v, operator=">=")],
|
||||
"<=": lambda v: [VersionBoundary(version=v, operator="<=")],
|
||||
"<": lambda v: [VersionBoundary(version=v, operator="<")],
|
||||
"=": VersionBoundary.equal,
|
||||
"~": VersionBoundary.tilde,
|
||||
"^": VersionBoundary.caret,
|
||||
None: VersionBoundary.equal,
|
||||
}
|
||||
|
||||
for match in RANGE_SPECIFIER_SIMPLE.finditer(specifier_string):
|
||||
operator, version_string = match.group("operator", "version")
|
||||
|
||||
for boundary in handler[operator](Version.parse(version_string)):
|
||||
yield boundary
|
||||
|
||||
|
||||
def parse_range(range_string):
|
||||
"""Parse full NPM version range specification::
|
||||
|
||||
>>> empty = parse_range(""); list(map(str, empty))
|
||||
[]
|
||||
>>> simple = parse_range("^1.0"); list(map(str, simple))
|
||||
['>=1.0', '<2']
|
||||
>>> hyphen = parse_range("1.0 - 2.0"); list(map(str, hyphen))
|
||||
['>=1.0', '<2.1']
|
||||
|
||||
This method implements the ``range`` part of the grammar:
|
||||
https://docs.npmjs.com/misc/semver#range-grammar.
|
||||
|
||||
Arguments:
|
||||
range_string (str): The range specification to parse.
|
||||
|
||||
Returns:
|
||||
Iterable[VersionBoundary]: Parsed boundaries.
|
||||
|
||||
Raises:
|
||||
UnsupportedVersionToken: ``||`` is present in range_string.
|
||||
"""
|
||||
|
||||
HYPHEN = " - "
|
||||
|
||||
# FIXME: rpm should be able to process OR in dependencies
|
||||
# This error reporting kept for backward compatibility
|
||||
if "||" in range_string:
|
||||
raise UnsupportedVersionToken(range_string)
|
||||
|
||||
if HYPHEN in range_string:
|
||||
version_pair = map(Version.parse, range_string.split(HYPHEN, 2))
|
||||
return VersionBoundary.hyphen(*version_pair)
|
||||
|
||||
elif range_string != "":
|
||||
return parse_simple_seq(range_string)
|
||||
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def unify_range(boundary_iter):
|
||||
"""Calculate largest allowed continuous version range from a set of boundaries::
|
||||
|
||||
>>> unify_range([])
|
||||
()
|
||||
>>> _ = unify_range(parse_range("=1.2.3 <2")); tuple(map(str, _))
|
||||
('>=1.2.3', '<1.2.4')
|
||||
>>> _ = unify_range(parse_range("~1.2 <1.2.5")); tuple(map(str, _))
|
||||
('>=1.2', '<1.2.5')
|
||||
|
||||
Arguments:
|
||||
boundary_iter (Iterable[VersionBoundary]): The version boundaries to unify.
|
||||
|
||||
Returns:
|
||||
(VersionBoundary, VersionBoundary):
|
||||
Lower and upper boundary of the unified range.
|
||||
"""
|
||||
|
||||
# Drop boundaries with empty version
|
||||
boundary_iter = (
|
||||
boundary for boundary in boundary_iter if not boundary.version.empty
|
||||
)
|
||||
|
||||
# Split input sequence into upper/lower boundaries
|
||||
lower_list, upper_list = [], []
|
||||
for boundary in boundary_iter:
|
||||
if boundary.lower:
|
||||
lower_list.append(boundary)
|
||||
elif boundary.upper:
|
||||
upper_list.append(boundary)
|
||||
else:
|
||||
msg = "Unsupported boundary for unify_range: {0}".format(boundary)
|
||||
raise ValueError(msg)
|
||||
|
||||
# Select maximum from lower boundaries and minimum from upper boundaries
|
||||
intermediate = (
|
||||
max(lower_list) if lower_list else None,
|
||||
min(upper_list) if upper_list else None,
|
||||
)
|
||||
|
||||
return tuple(filter(None, intermediate))
|
||||
|
||||
|
||||
def rpm_format(requirement, version_spec="*"):
|
||||
"""Format requirement as RPM boolean dependency::
|
||||
|
||||
>>> rpm_format("nodejs(engine)")
|
||||
'nodejs(engine)'
|
||||
>>> rpm_format("npm(foo)", ">=1.0.0")
|
||||
'npm(foo) >= 1.0.0'
|
||||
>>> rpm_format("npm(bar)", "~1.2")
|
||||
'(npm(bar) >= 1.2 with npm(bar) < 1.3)'
|
||||
|
||||
Arguments:
|
||||
requirement (str): The name of the requirement.
|
||||
version_spec (str): The NPM version specification for the requirement.
|
||||
|
||||
Returns:
|
||||
str: Formatted requirement.
|
||||
"""
|
||||
|
||||
TEMPLATE = "{name} {boundary.operator} {boundary.version!s}"
|
||||
|
||||
try:
|
||||
boundary_tuple = unify_range(parse_range(version_spec))
|
||||
|
||||
except UnsupportedVersionToken:
|
||||
# FIXME: Typos and print behavior kept for backward compatibility
|
||||
warning_lines = [
|
||||
"WARNING: The {requirement} dependency contains an OR (||) dependency: '{version_spec}.",
|
||||
"Please manually include a versioned dependency in your spec file if necessary",
|
||||
]
|
||||
warning = "\n".join(warning_lines).format(
|
||||
requirement=requirement, version_spec=version_spec
|
||||
)
|
||||
print(warning, end="", file=sys.stderr)
|
||||
|
||||
return requirement
|
||||
|
||||
formatted = [
|
||||
TEMPLATE.format(name=requirement, boundary=boundary)
|
||||
for boundary in boundary_tuple
|
||||
]
|
||||
|
||||
if len(formatted) > 1:
|
||||
return "({0})".format(" with ".join(formatted))
|
||||
elif len(formatted) == 1:
|
||||
return formatted[0]
|
||||
else:
|
||||
return requirement
|
||||
|
||||
|
||||
def has_only_bundled_dependencies(module_dir_path):
|
||||
"""Determines if the module contains only bundled dependencies.
|
||||
|
||||
Dependencies are considered un-bundled when they are symlinks
|
||||
pointing outside the root module's tree.
|
||||
|
||||
Arguments:
|
||||
module_dir_path (str):
|
||||
Path to the module directory (directory with ``package.json``).
|
||||
|
||||
Returns:
|
||||
bool: True if all dependencies are bundled, False otherwise.
|
||||
"""
|
||||
|
||||
module_root_path = os.path.abspath(module_dir_path)
|
||||
dependency_root_path = os.path.join(module_root_path, "node_modules")
|
||||
|
||||
try:
|
||||
dependency_path_iter = (
|
||||
os.path.join(dependency_root_path, basename)
|
||||
for basename in os.listdir(dependency_root_path)
|
||||
)
|
||||
bundled_dependency_iter = (
|
||||
os.path.realpath(path)
|
||||
for path in dependency_path_iter
|
||||
if not os.path.islink(path) or path.startswith(module_root_path)
|
||||
)
|
||||
|
||||
return any(bundled_dependency_iter)
|
||||
except OSError: # node_modules does not exist
|
||||
return False
|
||||
|
||||
|
||||
def extract_dependencies(metadata_path, optional=False):
|
||||
"""Extract all dependencies in RPM format from package metadata.
|
||||
|
||||
Arguments:
|
||||
metadata_path (str): Path to package metadata (``package.json``).
|
||||
optional (bool):
|
||||
If True, extract ``optionalDependencies``
|
||||
instead of ``dependencies``.
|
||||
|
||||
Yields:
|
||||
RPM-formatted dependencies.
|
||||
|
||||
Raises:
|
||||
TypeError: Invalid dependency data type.
|
||||
"""
|
||||
|
||||
if has_only_bundled_dependencies(os.path.dirname(metadata_path)):
|
||||
return # skip
|
||||
|
||||
# Read metadata
|
||||
try:
|
||||
with open(metadata_path, mode="r") as metadata_file:
|
||||
metadata = json.load(metadata_file)
|
||||
except OSError: # Invalid metadata file
|
||||
return # skip
|
||||
|
||||
# Report required NodeJS version with required dependencies
|
||||
if not optional:
|
||||
try:
|
||||
yield rpm_format("nodejs(engine)", metadata["engines"]["node"])
|
||||
except KeyError: # NodeJS engine version unspecified
|
||||
yield rpm_format("nodejs(engine)")
|
||||
|
||||
# Report listed dependencies
|
||||
kind = "optionalDependencies" if optional else "dependencies"
|
||||
container = metadata.get(kind, {})
|
||||
|
||||
if isinstance(container, dict):
|
||||
for name, version_spec in container.items():
|
||||
yield rpm_format(REQUIREMENT_NAME_TEMPLATE.format(name=name), version_spec)
|
||||
|
||||
elif isinstance(container, list):
|
||||
for name in container:
|
||||
yield rpm_format(REQUIREMENT_NAME_TEMPLATE.format(name=name))
|
||||
|
||||
elif isinstance(container, str):
|
||||
yield rpm_format(REQUIREMENT_NAME_TEMPLATE.format(name=name))
|
||||
|
||||
else:
|
||||
raise TypeError("invalid package.json: dependencies not a valid type")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
nested = (
|
||||
extract_dependencies(path.strip(), optional="--optional" in sys.argv)
|
||||
for path in sys.stdin
|
||||
)
|
||||
flat = chain.from_iterable(nested)
|
||||
# Ignore parentheses around the requirements when sorting
|
||||
ordered = sorted(flat, key=lambda s: s.strip("()"))
|
||||
|
||||
print(*ordered, sep="\n")
|
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (nodejs-packaging-fedora-25.tar.xz) = ba82999a2ac41114f2925be7a8fe9602e9ac17474b4c4b29de888f2eec9f9ca4ec7fad0e830f763426e1c5026b212bd1d2ddc1d19dbad74ac13fb77d36f85b80
|
||||
SHA512 (test.tar.gz) = dfbda67b8741f1ca36bf63b2e842f81ba07381b3d92e75fa7e29f8e456543b4cae55e95785902f31a14ae4d0b7e89161ba04c0c10c2fff617b4ae9607c91e599
|
||||
|
4
test/bundled/node_modules/test100/package.json
generated
vendored
Normal file
4
test/bundled/node_modules/test100/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "test100",
|
||||
"version": "1.3.5"
|
||||
}
|
4
test/bundled/node_modules/test101/package.json
generated
vendored
Normal file
4
test/bundled/node_modules/test101/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "test101",
|
||||
"version": "2.1.4"
|
||||
}
|
0
test/bundled/nodejs.prov.err.exp
Normal file
0
test/bundled/nodejs.prov.err.exp
Normal file
3
test/bundled/nodejs.prov.out.exp
Normal file
3
test/bundled/nodejs.prov.out.exp
Normal file
@ -0,0 +1,3 @@
|
||||
bundled(nodejs-test100) = 1.3.5
|
||||
bundled(nodejs-test101) = 2.1.4
|
||||
npm(test) = 4.5.6
|
0
test/bundled/nodejs.req.err.exp
Normal file
0
test/bundled/nodejs.req.err.exp
Normal file
1
test/bundled/nodejs.req.out.exp
Normal file
1
test/bundled/nodejs.req.out.exp
Normal file
@ -0,0 +1 @@
|
||||
|
11
test/bundled/package.json.in
Normal file
11
test/bundled/package.json.in
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "test",
|
||||
"version": "4.5.6",
|
||||
"engines": {
|
||||
"node": ">=6 <10"
|
||||
},
|
||||
"dependencies": {
|
||||
"test100": "^1.2.3",
|
||||
"test101": ">=2.1"
|
||||
}
|
||||
}
|
18
test/run
Executable file
18
test/run
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
ln -sf nodejs.req nodejs_req.py
|
||||
"$(command -v python2 || echo :)" -m doctest nodejs_req.py || exit 1
|
||||
"$(command -v python3 || echo :)" -m doctest nodejs_req.py || exit 1
|
||||
|
||||
for test in unbundled bundled
|
||||
do
|
||||
sed -e "s|//.*$||" < test/$test/package.json.in > test/$test/package.json
|
||||
|
||||
echo test/$test/package.json | ./nodejs.prov test/$test/package.json > test/$test/nodejs.prov.out 2> test/$test/nodejs.prov.err
|
||||
diff -uw test/$test/nodejs.prov.err.exp test/$test/nodejs.prov.err || exit 1
|
||||
diff -uw test/$test/nodejs.prov.out.exp test/$test/nodejs.prov.out || exit 1
|
||||
|
||||
echo test/$test/package.json | ./nodejs.req test/$test/package.json > test/$test/nodejs.req.out 2> test/$test/nodejs.req.err
|
||||
diff -uw test/$test/nodejs.req.err.exp test/$test/nodejs.req.err || exit 1
|
||||
diff -uw test/$test/nodejs.req.out.exp test/$test/nodejs.req.out || exit 1
|
||||
done
|
0
test/unbundled/nodejs.prov.err.exp
Normal file
0
test/unbundled/nodejs.prov.err.exp
Normal file
1
test/unbundled/nodejs.prov.out.exp
Normal file
1
test/unbundled/nodejs.prov.out.exp
Normal file
@ -0,0 +1 @@
|
||||
npm(test) = 4.5.6
|
2
test/unbundled/nodejs.req.err.exp
Normal file
2
test/unbundled/nodejs.req.err.exp
Normal file
@ -0,0 +1,2 @@
|
||||
WARNING: The npm(test900) dependency contains an OR (||) dependency: '^1.2 || ^2.2.
|
||||
Please manually include a versioned dependency in your spec file if necessary
|
74
test/unbundled/nodejs.req.out.exp
Normal file
74
test/unbundled/nodejs.req.out.exp
Normal file
@ -0,0 +1,74 @@
|
||||
(nodejs(engine) >= 6 with nodejs(engine) < 10)
|
||||
(npm(test100) >= 1 with npm(test100) < 2)
|
||||
(npm(test101) >= 1 with npm(test101) < 2)
|
||||
(npm(test102) >= 1 with npm(test102) < 2)
|
||||
(npm(test103) >= 1 with npm(test103) < 2)
|
||||
(npm(test104) >= 1.2 with npm(test104) < 1.3)
|
||||
(npm(test105) >= 1.2 with npm(test105) < 1.3)
|
||||
(npm(test106) >= 1.2 with npm(test106) < 1.3)
|
||||
(npm(test107) >= 1.2 with npm(test107) < 1.3)
|
||||
(npm(test108) >= 1.2.3 with npm(test108) < 1.2.4)
|
||||
(npm(test109) >= 1.2.3 with npm(test109) < 1.2.4)
|
||||
(npm(test110) >= 1.2.3 with npm(test110) < 1.2.4)
|
||||
(npm(test111) >= 1.2.3 with npm(test111) < 1.2.4)
|
||||
npm(test200) > 1
|
||||
npm(test201) > 1.2
|
||||
npm(test202) > 1.2.3
|
||||
npm(test203) >= 1
|
||||
npm(test204) >= 1.2
|
||||
npm(test205) >= 1.2.3
|
||||
npm(test206) < 2
|
||||
npm(test207) < 2.3
|
||||
npm(test208) < 2.3.4
|
||||
npm(test209) <= 2
|
||||
npm(test210) <= 2.3
|
||||
npm(test211) <= 2.3.4
|
||||
(npm(test300) > 1 with npm(test300) < 2)
|
||||
(npm(test301) > 1.2 with npm(test301) < 2.3)
|
||||
(npm(test302) > 1.2.3 with npm(test302) < 2.3.4)
|
||||
(npm(test303) >= 1 with npm(test303) <= 2)
|
||||
(npm(test304) >= 1.2 with npm(test304) <= 2.3)
|
||||
(npm(test305) >= 1.2.3 with npm(test305) <= 2.3.4)
|
||||
(npm(test306) > 1 with npm(test306) < 2)
|
||||
(npm(test307) > 1.2 with npm(test307) < 2.3)
|
||||
(npm(test308) > 1.2.3 with npm(test308) < 2.3.4)
|
||||
(npm(test309) >= 1 with npm(test309) <= 2)
|
||||
(npm(test310) >= 1.2 with npm(test310) <= 2.3)
|
||||
(npm(test311) >= 1.2.3 with npm(test311) <= 2.3.4)
|
||||
(npm(test400) >= 1.2.3 with npm(test400) <= 2.3.4)
|
||||
(npm(test401) >= 1.2.3 with npm(test401) < 2.4)
|
||||
(npm(test402) >= 1.2.3 with npm(test402) < 3)
|
||||
(npm(test403) >= 1.2 with npm(test403) <= 2.3.4)
|
||||
(npm(test404) >= 1 with npm(test404) <= 2.3.4)
|
||||
(npm(test405) >= 1.2 with npm(test405) < 2.4)
|
||||
(npm(test406) >= 1.2 with npm(test406) < 3)
|
||||
(npm(test407) >= 1 with npm(test407) < 2.4)
|
||||
(npm(test408) >= 1 with npm(test408) < 3)
|
||||
(npm(test500) >= 1.2 with npm(test500) < 1.3)
|
||||
(npm(test501) >= 1.2 with npm(test501) < 1.3)
|
||||
(npm(test502) >= 1 with npm(test502) < 2)
|
||||
(npm(test503) >= 1 with npm(test503) < 2)
|
||||
npm(test504)
|
||||
npm(test505)
|
||||
(npm(test600) >= 1.2.3 with npm(test600) < 1.3)
|
||||
(npm(test601) >= 1.2 with npm(test601) < 1.3)
|
||||
(npm(test602) >= 1.2 with npm(test602) < 1.3)
|
||||
(npm(test603) >= 1 with npm(test603) < 2)
|
||||
(npm(test604) >= 1 with npm(test604) < 2)
|
||||
(npm(test700) >= 1.2.3 with npm(test700) < 2)
|
||||
(npm(test701) >= 0.2.3 with npm(test701) < 0.3)
|
||||
(npm(test702) >= 0.0.3 with npm(test702) < 0.0.4)
|
||||
(npm(test703) >= 1.2 with npm(test703) < 2)
|
||||
(npm(test704) >= 1.2 with npm(test704) < 2)
|
||||
(npm(test705) >= 0.1 with npm(test705) < 0.2)
|
||||
(npm(test706) >= 0.1 with npm(test706) < 0.2)
|
||||
(npm(test707) >= 1 with npm(test707) < 2)
|
||||
(npm(test708) >= 1 with npm(test708) < 2)
|
||||
npm(test709) < 0.1
|
||||
npm(test710) < 0.1
|
||||
npm(test711) < 1
|
||||
npm(test712) < 1
|
||||
npm(test750) >= 0.10
|
||||
(npm(test751) >= 0.10 with npm(test751) <= 6)
|
||||
(npm(test800) > 1.2 with npm(test800) < 1.9)
|
||||
npm(test900)
|
108
test/unbundled/package.json.in
Normal file
108
test/unbundled/package.json.in
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"name": "test",
|
||||
"version": "4.5.6",
|
||||
"engines": {
|
||||
"node": ">=6 <10"
|
||||
},
|
||||
"dependencies": {
|
||||
// Single version
|
||||
"test100": "1",
|
||||
"test101": "=1",
|
||||
"test102": "v1",
|
||||
"test103": "=v1",
|
||||
"test104": "1.2",
|
||||
"test105": "=1.2",
|
||||
"test106": "v1.2",
|
||||
"test107": "=v1.2",
|
||||
"test108": "1.2.3",
|
||||
"test109": "=1.2.3",
|
||||
"test110": "v1.2.3",
|
||||
"test111": "=v1.2.3",
|
||||
|
||||
// Ranges with one comparator
|
||||
"test200": ">1",
|
||||
"test201": ">1.2",
|
||||
"test202": ">1.2.3",
|
||||
"test203": ">=1",
|
||||
"test204": ">=1.2",
|
||||
"test205": ">=1.2.3",
|
||||
"test206": "<2",
|
||||
"test207": "<2.3",
|
||||
"test208": "<2.3.4",
|
||||
"test209": "<=2",
|
||||
"test210": "<=2.3",
|
||||
"test211": "<=2.3.4",
|
||||
|
||||
// Ranges with two comparators
|
||||
"test300": ">1 <2",
|
||||
"test301": ">1.2 <2.3",
|
||||
"test302": ">1.2.3 <2.3.4",
|
||||
"test303": ">=1 <=2",
|
||||
"test304": ">=1.2 <=2.3",
|
||||
"test305": ">=1.2.3 <=2.3.4",
|
||||
"test306": "<2 >1",
|
||||
"test307": "<2.3 >1.2",
|
||||
"test308": "<2.3.4 >1.2.3",
|
||||
"test309": "<=2 >=1",
|
||||
"test310": "<=2.3 >=1.2",
|
||||
"test311": "<=2.3.4 >=1.2.3",
|
||||
|
||||
// Hyphen ranges
|
||||
"test400": "1.2.3 - 2.3.4",
|
||||
"test401": "1.2.3 - 2.3",
|
||||
"test402": "1.2.3 - 2",
|
||||
"test403": "1.2 - 2.3.4",
|
||||
"test404": "1 - 2.3.4",
|
||||
"test405": "1.2 - 2.3",
|
||||
"test406": "1.2 - 2",
|
||||
"test407": "1 - 2.3",
|
||||
"test408": "1 - 2",
|
||||
|
||||
// X-Ranges
|
||||
"test500": "1.2.x",
|
||||
"test501": "1.2.*",
|
||||
"test502": "1.x",
|
||||
"test503": "1.*",
|
||||
"test504": "*",
|
||||
"test505": "",
|
||||
|
||||
// Tilde ranges
|
||||
"test600": "~1.2.3",
|
||||
"test601": "~1.2.x",
|
||||
"test602": "~1.2",
|
||||
"test603": "~1.x",
|
||||
"test604": "~1",
|
||||
|
||||
// Caret ranges
|
||||
"test700": "^1.2.3",
|
||||
"test701": "^0.2.3",
|
||||
"test702": "^0.0.3",
|
||||
"test703": "^1.2.x",
|
||||
"test704": "^1.2",
|
||||
"test705": "^0.1.x",
|
||||
"test706": "^0.1",
|
||||
"test707": "^1.x",
|
||||
"test708": "^1",
|
||||
"test709": "^0.0.x",
|
||||
"test710": "^0.0",
|
||||
"test711": "^0.x",
|
||||
"test712": "^0",
|
||||
|
||||
// Space after the operator
|
||||
// (the grammar does not permit this, but it is accepted in practice)
|
||||
"test750": ">= 0.10",
|
||||
"test751": ">= 0.10 <= 6",
|
||||
|
||||
// More than two comparators in a set
|
||||
// (no reason for this to ever appear, but it is permitted)
|
||||
"test800": ">1.2 <2.0 <1.9",
|
||||
|
||||
// The following cases are not implemented currently...
|
||||
|
||||
// Multiple comparator sets separated by ||
|
||||
"test900": "^1.2 || ^2.2"
|
||||
|
||||
// The whole pre-release stuff: https://docs.npmjs.com/misc/semver//prerelease-tags
|
||||
// which is not even enumerated here because it is so complex.
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user