├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bin ├── npm2PKGBUILD ├── npm2archinstall ├── npm2archpkg └── npm2aurball ├── index.js ├── lib ├── createPkg.js ├── fetchJSON.js ├── handleError.js └── npm2PKGBUILD.js ├── package.json └── test └── npm2arch.js /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | node-version: [10.x, 12.x, 14.x, 15.x] 13 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - run: npm install 21 | - run: npm run build --if-present 22 | - run: npm test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | test/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011 Filirom1 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | npm2arch 2 | ======== 3 | 4 | Convert [npm](https://www.npmjs.com/) packages/[package.json](https://docs.npmjs.com/files/package.json) into a [PKGBUILD](https://www.archlinux.org/pacman/PKGBUILD.5.html) for [Arch Linux](https://www.archlinux.org/) integration. 5 | 6 | This is a fork of the unmaintained [Filirom1/npm2arch](https://github.com/Filirom1/npm2arch). 7 | 8 | 9 | Install 10 | ------- 11 | ### From AUR 12 | yaourt -S [nodejs-npm2arch](https://aur.archlinux.org/packages/nodejs-npm2arch/) 13 | 14 | 15 | ### From sources 16 | 17 | git clone https://github.com/Filirom1/npm2arch 18 | cd npm2arch 19 | [sudo] npm install -g 20 | 21 | 22 | Usage 23 | ----- 24 | 25 | ### npm2PKGBUILD 26 | 27 | Transform an npm package into an Arch Linux `PKGBUILD` 28 | 29 | npm2PKGBUILD $NPM_NAME > PKGBUILD 30 | makepkg 31 | pacman -U nodejs-$NPM_NAME-$VERSION-any.pkg.tar.xz 32 | 33 | 34 | ### npm2aurball 35 | 36 | Transform an npm package into an AUR tarball using `mkaurball` 37 | 38 | npm2aurball $NPM_NAME 39 | 40 | 41 | ### npm2archpkg 42 | 43 | Transform an npm package into an Arch Linux package archive 44 | 45 | npm2archpkg $NPM_NAME 46 | pacman -U nodejs-$NPM_NAME-$VERSION-any.pkg.tar.xz 47 | 48 | 49 | ### npm2archinstall 50 | 51 | Install an npm package with pacman 52 | 53 | npm2archinstall $NPM_NAME 54 | 55 | 56 | License 57 | ------- 58 | 59 | npm2arch is licensed under the [MIT License](https://github.com/Filirom1/npm2arch/blob/master/LICENSE). 60 | -------------------------------------------------------------------------------- /bin/npm2PKGBUILD: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var npm2arch = require('../lib/npm2PKGBUILD'); 3 | var handleError = require('../lib/handleError'); 4 | 5 | if (process.argv.length != 3) { 6 | console.error('Usage: npm2PKGBUILD `npm-name` > PKGBUILD'); 7 | process.exit(-1); 8 | } 9 | 10 | var npmName = process.argv[2]; 11 | 12 | // Show on the console the PKGBUILD 13 | npm2arch(npmName) 14 | .then(pkgbuild => console.log(pkgbuild)) 15 | .catch(err => handleError(err)); 16 | -------------------------------------------------------------------------------- /bin/npm2archinstall: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var createPkg = require('../lib/createPkg'), 3 | handleError = require('../lib/handleError'), 4 | fs = require('fs'), 5 | spawn = require('child_process').spawn; 6 | 7 | if (process.argv.length != 3) { 8 | console.error('Usage: npm2archinstall `npm-name`'); 9 | process.exit(-1); 10 | } 11 | 12 | var npmName = process.argv[2]; 13 | 14 | createPkg(npmName) 15 | .then(pkgFile => { 16 | console.log('\nsudo pacman -U ' + pkgFile); 17 | var pacman = spawn('sudo', ['pacman', '-U', pkgFile], { stdio: 'inherit' }); 18 | pacman.on('exit', function(code) { 19 | fs.unlink(pkgFile, function(err) { 20 | if (err) throw err; 21 | if (code !== 0) process.exit(code); 22 | process.exit(0); 23 | }); 24 | }); 25 | }) 26 | .catch(err => handleError(err)); 27 | -------------------------------------------------------------------------------- /bin/npm2archpkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var createPkg = require('../lib/createPkg'); 3 | var handleError = require('../lib/handleError'); 4 | 5 | if (process.argv.length < 3) { 6 | console.error('Usage: npm2archpkg `npm-name` [-f or any makepkg arguments]'); 7 | process.exit(-1); 8 | } 9 | 10 | var npmName = process.argv[2]; 11 | var otherArgv = process.argv.slice(3, process.argv.length); 12 | 13 | createPkg(npmName, otherArgv) 14 | .then(pkgFile => console.log('Package created: ' + pkgFile)) 15 | .catch(err => handleError(err)); 16 | -------------------------------------------------------------------------------- /bin/npm2aurball: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var createPkg = require('../lib/createPkg'); 3 | var handleError = require('../lib/handleError'); 4 | 5 | if (process.argv.length < 3) { 6 | console.error('Usage: npm2aurball `npm-name`'); 7 | process.exit(-1); 8 | } 9 | 10 | var npmName = process.argv[2]; 11 | 12 | createPkg(npmName, 'aurball') 13 | .then(pkgFile => console.log('AUR tarball created: ' + pkgFile)) 14 | .catch(err => handleError(err)); 15 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var npm2arch = require('./lib/npm2PKGBUILD'), 2 | createPkg = require('./lib/createPkg'); 3 | 4 | module.exports = { 5 | npm2PKGBUILD: npm2arch, 6 | createPkg: createPkg 7 | }; 8 | -------------------------------------------------------------------------------- /lib/createPkg.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const fs = require('fs-extra'); 3 | const path = require('path'); 4 | const util = require('util'); 5 | const { spawnSync } = require('child_process'); 6 | const npm2arch = require('./npm2PKGBUILD'); 7 | 8 | module.exports = (npmName, makePkgArgv, options) => { 9 | const aurball = makePkgArgv === 'aurball'; 10 | if (aurball) { 11 | makePkgArgv = []; 12 | } 13 | if (!makePkgArgv) { 14 | makePkgArgv = []; 15 | } 16 | if (!options) { 17 | options = { verbose: true }; 18 | } 19 | const { verbose } = options; 20 | // Create a tmp directory to work on 21 | const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'npm2archinstall-')); 22 | 23 | // Create a package for archlinux with makepkg cmd 24 | const promise = npm2arch(npmName, options) 25 | .then(pkgbuild => 26 | // Write the PKGBUILD file in the tmpDir 27 | fs.writeFile(path.join(tmpDir, 'PKGBUILD'), pkgbuild) 28 | ) 29 | .then(() => { 30 | // Spawn makepkg/mkaurball 31 | const stdio = verbose ? 'inherit' : 'ignore'; 32 | const opts = { cwd: tmpDir, env: process.env, setsid: false, stdio }; 33 | const cmd = aurball ? 'mkaurball' : 'makepkg'; 34 | const child = spawnSync(cmd, makePkgArgv, opts); 35 | if (child.status !== 0) { 36 | throw new Error( 37 | `Bad status code returned from \`${makepkg}\`: ${child.status}` 38 | ); 39 | } 40 | }) 41 | .then(() => 42 | // Get the package file name 43 | fs.readdir(tmpDir) 44 | ) 45 | .then(files => { 46 | const pkgFile = files.filter(file => file.indexOf('nodejs-') === 0)[0]; 47 | const newPkgFile = path.join(process.cwd(), path.basename(pkgFile)); 48 | if (fs.existsSync(newPkgFile)) { 49 | fs.unlinkSync(newPkgFile); 50 | } 51 | fs.moveSync(path.join(tmpDir, pkgFile), newPkgFile); 52 | return newPkgFile; 53 | }); 54 | promise.then(() => fs.remove(tmpDir)).catch(() => fs.remove(tmpDir)); 55 | return promise; 56 | }; 57 | -------------------------------------------------------------------------------- /lib/fetchJSON.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | 3 | module.exports = function fetchJSON(url) { 4 | return new Promise((resolve, reject) => { 5 | const req = https.get(url, res => { 6 | let body = ''; 7 | res.on('data', chunk => (body += chunk)); 8 | res.on('end', () => { 9 | if (200 <= res.statusCode && res.statusCode < 300) { 10 | const json = JSON.parse(body); 11 | resolve(json); 12 | } else { 13 | reject(res.statusCode); 14 | } 15 | }); 16 | }); 17 | req.on('error', error => reject(error)); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /lib/handleError.js: -------------------------------------------------------------------------------- 1 | module.exports = function handleError(err) { 2 | console.error(err); 3 | process.exit(-1); 4 | }; 5 | -------------------------------------------------------------------------------- /lib/npm2PKGBUILD.js: -------------------------------------------------------------------------------- 1 | const fetchJSON = require('./fetchJSON'); 2 | 3 | // transform pkg.json of `npmName` into a PKGBUILD and returns a Promise 4 | module.exports = (npmName, options) => { 5 | if (typeof options === 'function') { 6 | options = null; 7 | } 8 | if (!options) { 9 | options = {}; 10 | } 11 | const url = `https://registry.npmjs.org/${npmName}/latest`; 12 | return fetchJSON(url) 13 | .then(pkg => { 14 | pkg.nameLowerCase = pkg.name.toLowerCase(); 15 | if (!pkg.homepage) { 16 | pkg.homepage = pkg.url; 17 | } 18 | if (pkg.repository != null ? pkg.repository.url : undefined) { 19 | if (!pkg.homepage) { 20 | pkg.homepage = pkg.repository.url 21 | .replace(/^git(@|:\/\/)/, 'https://') 22 | .replace(/\.git$/, '') 23 | .replace(/(\.\w*)\:/g, '$1/'); 24 | } 25 | } 26 | pkg.depends = (options.depends || []).map(d => ` '${d}'`).join(''); 27 | pkg.optdepends = (options.optdepends || []) 28 | .map(o => { 29 | const key = Object.keys(o)[0]; 30 | const value = o[key]; 31 | return `${key}: ${value}`; 32 | }) 33 | .map(d => `'${d}'`) 34 | .join(' '); 35 | pkg.archVersion = pkg.version.replace(/-/, '_'); 36 | pkg.license = pkg.license || (pkg.licenses || []).map(l => l.type); 37 | return pkg; 38 | }) 39 | .then( 40 | pkg => `_npmname=${pkg.name} 41 | _npmver=${pkg.version} 42 | pkgname=nodejs-${pkg.nameLowerCase} # All lowercase 43 | pkgver=${pkg.archVersion} 44 | pkgrel=1 45 | pkgdesc="${pkg.description}" 46 | arch=(any) 47 | url="${pkg.homepage}" 48 | license=(${pkg.license}) 49 | depends=('nodejs' 'npm'${pkg.depends}) 50 | optdepends=(${pkg.optdepends}) 51 | source=(https://registry.npmjs.org/$_npmname/-/$_npmname-$_npmver.tgz) 52 | noextract=($_npmname-$_npmver.tgz) 53 | sha1sums=(${pkg.dist.shasum}) 54 | 55 | package() { 56 | cd $srcdir 57 | local _npmdir="$pkgdir/usr/lib/node_modules/" 58 | mkdir -p $_npmdir 59 | cd $_npmdir 60 | npm install -g --prefix "$pkgdir/usr" $_npmname@$_npmver 61 | chown -R root:root "$pkgdir" 62 | } 63 | 64 | # vim:set ts=2 sw=2 et:` 65 | ) 66 | .catch(err => { 67 | throw new Error(`Registry returned ${err} for GET on ${url}`); 68 | }); 69 | }; 70 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Filirom1 ", 3 | "contributors": [ 4 | "Simon Legner " 5 | ], 6 | "name": "@simon04/npm2arch", 7 | "description": "Convert NPM package to a PKGBUILD for ArchLinux", 8 | "version": "2.2.0", 9 | "homepage": "https://github.com/simon04/npm2arch", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/simon04/npm2arch.git" 13 | }, 14 | "license": "MIT", 15 | "main": "index.js", 16 | "bin": { 17 | "npm2PKGBUILD": "bin/npm2PKGBUILD", 18 | "npm2aurball": "bin/npm2aurball", 19 | "npm2archpkg": "bin/npm2archpkg", 20 | "npm2archinstall": "bin/npm2archinstall" 21 | }, 22 | "preferGlobal": true, 23 | "dependencies": { 24 | "fs-extra": "^5.0.0" 25 | }, 26 | "devDependencies": { 27 | "hasbin": "^1.2.3", 28 | "mocha": "^5.0.1", 29 | "prettier": "^1.11.1", 30 | "vows": "~0.7.0" 31 | }, 32 | "prettier": { 33 | "singleQuote": true 34 | }, 35 | "scripts": { 36 | "test": "prettier --list-different $(git ls-files '*.js' 'bin/npm2*') && mocha --reporter spec --timeout 5000" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/npm2arch.js: -------------------------------------------------------------------------------- 1 | const { npm2PKGBUILD, createPkg } = require('../index'); 2 | const mocha = require('mocha'); 3 | const vows = require('vows'); 4 | const assert = require('assert'); 5 | const path = require('path'); 6 | const fs = require('fs-extra'); 7 | const hasbin = require('hasbin'); 8 | 9 | const cwd = process.cwd(); 10 | 11 | describe('Test npm2arch', function() { 12 | it('should create a PKGBUILD when calling npm2PKGBUILD with an existing package in npm', () => 13 | npm2PKGBUILD('npm2arch', { 14 | depends: ['curl', 'git'], 15 | optdepends: [{ phantomjs: 'browser-run test suite' }] 16 | }).then(pkgbuild => { 17 | assert.isNotNull(pkgbuild); 18 | assert.include(pkgbuild, 'license=(MIT)'); 19 | assert.include(pkgbuild, 'url="https://github.com/Filirom1/npm2arch"'); 20 | assert.include( 21 | pkgbuild, 22 | 'pkgdesc="Convert NPM package to a PKGBUILD for ArchLinux"' 23 | ); 24 | assert.include(pkgbuild, "depends=('nodejs' 'npm' 'curl' 'git')"); 25 | assert.include( 26 | pkgbuild, 27 | "optdepends=('phantomjs: browser-run test suite')" 28 | ); 29 | })); 30 | 31 | it('should put in lower case package name in UPPER CASE', () => 32 | npm2PKGBUILD('CM1').then(pkgbuild => { 33 | assert.isNotNull(pkgbuild); 34 | assert.include(pkgbuild, 'pkgname=nodejs-cm1'); 35 | })); 36 | 37 | it('should return an error when calling npm2PKGBUILD with a non existing package in npm', () => 38 | npm2PKGBUILD('fqkjsdfkqjs').catch(err => { 39 | assert.isNotNull(err); 40 | assert.equal( 41 | 'Registry returned 404 for GET on https://registry.npmjs.org/fqkjsdfkqjs/latest', 42 | err.message 43 | ); 44 | })); 45 | 46 | it('should create a package when calling createPkg with a real package name', function() { 47 | if (!hasbin.sync('makepkg')) { 48 | this.skip('mssing makepkg dependency'); 49 | } 50 | const randomId = (((1 + Math.random()) * 0x10000) | 0) 51 | .toString(16) 52 | .substring(1); 53 | const dir = `/tmp/test-npm2arch-${randomId}-dir/`; 54 | fs.mkdirSync(dir); 55 | process.chdir(dir); 56 | return createPkg('npm2arch', ['--source'], { verbose: false }, function( 57 | err, 58 | file 59 | ) { 60 | assert.isNull(err); 61 | assert.include(file, '/tmp/'); 62 | assert.include(file, '-dir/'); 63 | assert.include(file, 'nodejs-npm2arch-'); 64 | assert.include(file, '.src.tar.gz'); 65 | assert.isTrue(fs.existsSync(file)); 66 | fs.removeSync(path.dirname(file)); 67 | return done(); 68 | }); 69 | }); 70 | 71 | it('should create an AUR tarball when calling createPkg with a real package name', function() { 72 | if (!hasbin.sync('mkaurball')) { 73 | this.skip('missing mkaurball dependency'); 74 | } 75 | const randomId = (((1 + Math.random()) * 0x10000) | 0) 76 | .toString(16) 77 | .substring(1); 78 | const dir = `/tmp/test-npm2arch-${randomId}-dir/`; 79 | fs.mkdirSync(dir); 80 | process.chdir(dir); 81 | return createPkg('npm2arch', 'aurball', { verbose: false }).then(file => { 82 | assert.include(file, '/tmp/'); 83 | assert.include(file, '-dir/'); 84 | assert.include(file, 'nodejs-npm2arch-'); 85 | assert.include(file, '.src.tar.gz'); 86 | assert.isTrue(fs.existsSync(file)); 87 | fs.removeSync(path.dirname(file)); 88 | }); 89 | }); 90 | 91 | return it('should return an error when calling createPkg with a bad package name', () => 92 | createPkg('qsdfqsdfqsd', ['--source'], { verbose: false }).catch(err => { 93 | assert.isNotNull(err); 94 | assert.equal( 95 | 'Registry returned 404 for GET on https://registry.npmjs.org/qsdfqsdfqsd/latest', 96 | err.message 97 | ); 98 | })); 99 | }); 100 | --------------------------------------------------------------------------------