├── .gitignore ├── LICENSE ├── README.md ├── bin ├── npm2PKGBUILD ├── npm2archinstall ├── npm2archpkg └── npm2aurball ├── index.js ├── lib ├── createPkg.coffee └── npm2PKGBUILD.coffee ├── package.json └── test └── npm2arch.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /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 packages into a PKGBUILD for Archlinux integration. 5 | 6 | NPM package.json --> PKGBUILD for pacman 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 ArchLinux PKGBUILD 28 | 29 | npm2PKGBUILD `npm-name` > PKGBUILD 30 | makepkg 31 | pacman -U nodejs-`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 ArchLinux package archive 44 | 45 | npm2archpkg `npm-name` 46 | pacman -U nodejs-`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 | require('coffee-script'); 3 | var npm2arch = require('../lib/npm2PKGBUILD'); 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, function(err, pkgbuild){ 14 | if(err) { 15 | console.error(err.message); 16 | process.exit(-1); 17 | } 18 | console.log(pkgbuild); 19 | }); 20 | -------------------------------------------------------------------------------- /bin/npm2archinstall: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('coffee-script'); 3 | var createPkg = require('../lib/createPkg'), 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 | function handleError(err){ 15 | console.error(err); 16 | process.exit(-1); 17 | } 18 | 19 | createPkg(npmName, function(err, pkgFile){ 20 | if(err) handleError(err); 21 | // Install the pckage via a sudo pacman -U `pkgFile` 22 | console.log('\nsudo pacman -U ' + pkgFile); 23 | var pacman = spawn('sudo', ['pacman', '-U', pkgFile], {stdio: 'inherit'}); 24 | pacman.on('exit', function (code) { 25 | fs.unlink(pkgFile, function(err){ 26 | if(err) handleError(err); 27 | if (code !== 0) process.exit(code); 28 | process.exit(0); 29 | }) 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /bin/npm2archpkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('coffee-script'); 3 | var createPkg = require('../lib/createPkg'); 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 | function handleError(err){ 14 | console.error(err); 15 | process.exit(-1); 16 | } 17 | 18 | createPkg(npmName, otherArgv, function(err, pkgFile){ 19 | if(err) handleError(err); 20 | console.log("Package created: "+pkgFile); 21 | }); 22 | -------------------------------------------------------------------------------- /bin/npm2aurball: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('coffee-script'); 3 | var createPkg = require('../lib/createPkg'); 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 | function handleError(err){ 13 | console.error(err); 14 | process.exit(-1); 15 | } 16 | 17 | createPkg(npmName, 'aurball', function(err, pkgFile){ 18 | if(err) handleError(err); 19 | console.log("AUR tarball created: "+pkgFile); 20 | }); 21 | -------------------------------------------------------------------------------- /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.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs.extra' 2 | path = require 'path' 3 | util = require 'util' 4 | rimraf = require 'rimraf' 5 | {spawn} = require 'child_process' 6 | npm2arch = require './npm2PKGBUILD' 7 | UUID = require 'uuid-js' 8 | 9 | 10 | module.exports = (npmName, makePkgArgv, options, cb) -> 11 | if typeof makePkgArgv is 'function' 12 | cb = makePkgArgv 13 | makePkgArgv = null 14 | options = null 15 | if typeof options is 'function' 16 | cb = options 17 | options = null 18 | aurball = makePkgArgv == 'aurball' 19 | makePkgArgv = [] if aurball 20 | makePkgArgv or= [] 21 | options or= verbose: true 22 | verbose = options.verbose 23 | randomId = UUID.create() 24 | tmpDir = '/tmp/npm2archinstall-' + randomId 25 | 26 | # Create a package for archlinux with makepkg cmd 27 | npm2arch npmName, options, (err, pkgbuild)-> 28 | return cb err if err 29 | # Create a tmp directory to work on 30 | fs.mkdir tmpDir, '0755', (err)-> 31 | return cb err if err 32 | cb2 = -> 33 | arg = arguments 34 | # Delete the tmp directory 35 | rimraf tmpDir, (err) -> 36 | return cb err if err 37 | cb.apply(this, arg) 38 | 39 | # Write the PKGBUILD file in the tmpDir 40 | fs.writeFile path.join(tmpDir, "PKGBUILD"), pkgbuild, (err)-> 41 | return cb2 err if err 42 | # Spawn makepkg/mkaurball 43 | stdio = if verbose then 'inherit' else 'ignore' 44 | opts = cwd: tmpDir, env: process.env, setsid: false, stdio: stdio 45 | child = if aurball 46 | spawn 'mkaurball', makePkgArgv, opts 47 | else 48 | spawn 'makepkg', makePkgArgv, opts 49 | child.on 'exit', (code) -> 50 | makepkg = if aurball then 'mkaurball' else 'makepkg' 51 | return cb2 "Bad status code returned from `#{makepkg}`: #{code}" if code isnt 0 52 | # Get the package file name 53 | fs.readdir tmpDir, (err, files)-> 54 | return cb2 err if err 55 | pkgFile = (files.filter (file)-> file.indexOf('nodejs-') is 0)[0] 56 | newPkgFile = path.join(process.cwd(), path.basename pkgFile) 57 | fs.unlinkSync newPkgFile if fs.existsSync newPkgFile 58 | fs.move path.join(tmpDir, pkgFile), newPkgFile, (err)-> 59 | return cb2 err if err 60 | cb2 null, newPkgFile 61 | -------------------------------------------------------------------------------- /lib/npm2PKGBUILD.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env coffee 2 | npm = require 'npm' 3 | mustache = require 'mustache' 4 | fs = require 'fs' 5 | 6 | # transform pkg.json of `npmName` into a PKGBUILD 7 | # `cb` is called like this: `cb(err, pkgbuild)` 8 | module.exports = (npmName, options, cb) -> 9 | 10 | if typeof options is 'function' 11 | cb = options 12 | options = null 13 | 14 | options or= {} 15 | 16 | # Execute npm info `argv[0]` 17 | npm.load loglevel:'silent', (er)-> 18 | return cb(er) if er 19 | npm.commands.view [npmName], true, (er, json) -> 20 | return cb(er) if er 21 | parseNPM json 22 | 23 | # Parse the info json 24 | parseNPM = (data) -> 25 | version = Object.keys(data)[0] 26 | pkg = data[version] 27 | pkg = cleanup pkg 28 | pkg.nameLowerCase = pkg.name.toLowerCase() 29 | pkg.homepage or= pkg.url 30 | pkg.homepage or= pkg.repository.url.replace(/^git(@|:\/\/)/, 'http://').replace(/\.git$/, '').replace(/(\.\w*)\:/g, '$1\/') if pkg.repository?.url 31 | pkg.depends = options.depends 32 | pkg.optdepends = options.optdepends?.map (o)-> 33 | key = (Object.keys o)[0] 34 | value = o[key] 35 | return "#{key}: #{value}" 36 | pkg.archVersion = pkg.version.replace(/-/, '_') 37 | populateTemplate pkg 38 | 39 | # Populate the template 40 | populateTemplate = (pkg) -> 41 | cb null, mustache.to_html(template, pkg) 42 | 43 | template = '''_npmname={{{name}}} 44 | _npmver={{{version}}} 45 | pkgname=nodejs-{{{nameLowerCase}}} # All lowercase 46 | pkgver={{{archVersion}}} 47 | pkgrel=1 48 | pkgdesc=\"{{{description}}}\" 49 | arch=(any) 50 | url=\"{{{homepage}}}\" 51 | license=({{#licenses}}{{{type}}}{{/licenses}}) 52 | depends=('nodejs' 'npm' {{#depends}}'{{{.}}}' {{/depends}}) 53 | optdepends=({{#optdepends}}'{{{.}}}' {{/optdepends}}) 54 | source=(http://registry.npmjs.org/$_npmname/-/$_npmname-$_npmver.tgz) 55 | noextract=($_npmname-$_npmver.tgz) 56 | sha1sums=({{#dist}}{{{shasum}}}{{/dist}}) 57 | 58 | package() { 59 | cd $srcdir 60 | local _npmdir="$pkgdir/usr/lib/node_modules/" 61 | mkdir -p $_npmdir 62 | cd $_npmdir 63 | npm install -g --prefix "$pkgdir/usr" $_npmname@$_npmver 64 | } 65 | 66 | # vim:set ts=2 sw=2 et:''' 67 | 68 | # From NPM sources 69 | `function cleanup (data) { 70 | if (Array.isArray(data)) { 71 | if (data.length === 1) { 72 | data = data[0] 73 | } else { 74 | return data.map(cleanup) 75 | } 76 | } 77 | if (!data || typeof data !== "object") return data 78 | 79 | if (typeof data.versions === "object" 80 | && data.versions 81 | && !Array.isArray(data.versions)) { 82 | data.versions = Object.keys(data.versions || {}) 83 | } 84 | 85 | var keys = Object.keys(data) 86 | keys.forEach(function (d) { 87 | if (d.charAt(0) === "_") delete data[d] 88 | else if (typeof data[d] === "object") data[d] = cleanup(data[d]) 89 | }) 90 | keys = Object.keys(data) 91 | if (keys.length <= 3 92 | && data.name 93 | && (keys.length === 1 94 | || keys.length === 3 && data.email && data.url 95 | || keys.length === 2 && (data.email || data.url))) { 96 | data = unparsePerson(data) 97 | } 98 | return data 99 | } 100 | function unparsePerson (d) { 101 | if (typeof d === "string") return d 102 | return d.name 103 | + (d.email ? " <"+d.email+">" : "") 104 | + (d.url ? " ("+d.url+")" : "") 105 | }` 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Filirom1 ", 3 | "name": "npm2arch", 4 | "description": "Convert NPM package to a PKGBUILD for ArchLinux", 5 | "version": "0.1.19", 6 | "homepage": "https://github.com/Filirom1/npm2arch", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/Filirom1/npm2arch.git" 10 | }, 11 | "licenses": [ 12 | { 13 | "type": "MIT", 14 | "url": "http://www.opensource.org/licenses/MIT" 15 | } 16 | ], 17 | "main": "index.js", 18 | "bin": { 19 | "npm2PKGBUILD": "bin/npm2PKGBUILD", 20 | "npm2aurball": "bin/npm2aurball", 21 | "npm2archpkg": "bin/npm2archpkg", 22 | "npm2archinstall": "bin/npm2archinstall" 23 | }, 24 | "preferGlobal": true, 25 | "engines": { 26 | "node": ">0.8.0" 27 | }, 28 | "dependencies": { 29 | "coffee-script": "~1.6.2", 30 | "npm": "~1.2.15", 31 | "mustache": "~0.7.2", 32 | "rimraf": "~2.1.4", 33 | "fs.extra": "~1.2.0", 34 | "uuid-js": "~0.7.4" 35 | }, 36 | "devDependencies": { 37 | "mocha": "~1.8.2", 38 | "vows": "~0.7.0" 39 | }, 40 | "scripts": { 41 | "test": " ./node_modules/.bin/mocha --compilers coffee:coffee-script -R spec" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/npm2arch.coffee: -------------------------------------------------------------------------------- 1 | {npm2PKGBUILD, createPkg} = require '../index' 2 | mocha = require 'mocha' 3 | vows = require 'vows' 4 | assert = require 'assert' 5 | path = require 'path' 6 | fs = require 'fs' 7 | rimraf = require 'rimraf' 8 | 9 | cwd = process.cwd() 10 | 11 | describe 'Test npm2arch', -> 12 | 13 | it 'should create a PKGBUILD when calling npm2PKGBUILD with an existing package in npm', (done) -> 14 | npm2PKGBUILD 'npm2arch', depends: ['curl', 'git'], optdepends: [ phantomjs: 'browser-run test suite'], (err, pkgbuild) -> 15 | assert.isNull err 16 | assert.isNotNull pkgbuild 17 | assert.include pkgbuild, "license=(MIT)" 18 | assert.include pkgbuild, 'url="https://github.com/Filirom1/npm2arch"' 19 | assert.include pkgbuild, 'pkgdesc="Convert NPM package to a PKGBUILD for ArchLinux"' 20 | assert.include pkgbuild, "depends=('nodejs' 'curl' 'git' )" 21 | assert.include pkgbuild, "optdepends=('phantomjs: browser-run test suite' )" 22 | done() 23 | 24 | it 'should put in lower case package name in UPPER CASE', (done)-> 25 | npm2PKGBUILD 'CM1', (err, pkgbuild) -> 26 | assert.isNull err 27 | assert.isNotNull pkgbuild 28 | assert.include pkgbuild, "pkgname=nodejs-cm1" 29 | done() 30 | 31 | it 'should return an error when calling npm2PKGBUILD with a non existing package in npm', (done)-> 32 | npm2PKGBUILD 'fqkjsdfkqjs', (err, pkgbuild) -> 33 | assert.isNotNull err 34 | assert.equal '404 Not Found: fqkjsdfkqjs', err.message 35 | done() 36 | 37 | it 'should create a package when calling createPkg with a real package name', (done)-> 38 | randomId = (((1+Math.random())*0x10000)|0).toString(16).substring(1) 39 | dir = "/tmp/test-npm2arch-#{randomId}-dir/" 40 | fs.mkdirSync dir 41 | process.chdir dir 42 | createPkg 'npm2arch', ['--source'], verbose: false, (err, file) -> 43 | assert.isNull err 44 | assert.include file, '/tmp/' 45 | assert.include file, '-dir/' 46 | assert.include file, 'nodejs-npm2arch-' 47 | assert.include file, '.src.tar.gz' 48 | assert.isTrue fs.existsSync file 49 | rimraf.sync path.dirname file 50 | done() 51 | 52 | it 'should create an AUR tarball when calling createPkg with a real package name', (done)-> 53 | randomId = (((1+Math.random())*0x10000)|0).toString(16).substring(1) 54 | dir = "/tmp/test-npm2arch-#{randomId}-dir/" 55 | fs.mkdirSync dir 56 | process.chdir dir 57 | createPkg 'npm2arch', 'aurball', verbose: false, (err, file) -> 58 | assert.isNull err 59 | assert.include file, '/tmp/' 60 | assert.include file, '-dir/' 61 | assert.include file, 'nodejs-npm2arch-' 62 | assert.include file, '.src.tar.gz' 63 | assert.isTrue fs.existsSync file 64 | rimraf.sync path.dirname file 65 | done() 66 | 67 | it 'should return an error when calling createPkg with a bad package name', (done)-> 68 | createPkg 'qsdfqsdfqsd', ['--source'], verbose: false, (err, file) -> 69 | assert.isNotNull err 70 | assert.equal '404 Not Found: qsdfqsdfqsd', err.message 71 | done() 72 | --------------------------------------------------------------------------------