├── .gitignore ├── GNUmakefile ├── README.md ├── README.ru.md ├── bin └── npm2debian ├── debian-npm-ver ├── compat ├── control ├── dirs.in ├── install ├── links ├── rules └── watch.ex ├── debian-npm ├── compat ├── control ├── dirs.in ├── install ├── links ├── rules └── watch.ex ├── lib └── cli.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | RSYNC_ARIKON=arikon.dev.tools.yandex.net:/home/arikon/projects/bem/npm2debian 4 | rsync-arikon: 5 | rsync -az -e ssh --delete ./ $(RSYNC_ARIKON) 6 | 7 | .PHONY: rsync-arikon 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm2debian 2 | **npm2debian** is a command line tool to convert packages from npmjs.org repository to Debian packages. 3 | 4 | Contributions are welcome, we have [some tasks](https://github.com/arikon/npm2debian/issues) to do. 5 | 6 | ## Overview 7 | 8 | npm2debian [options] 9 | 10 | ## Options 11 | 12 | -h, --help : Help 13 | -o OUTPUT, --output=OUTPUT : Output directory 14 | --versioned : Build versioned debian package 15 | --no-package-prefix : Do not add prefix to Debian package name 16 | -m MAINTAINER, 17 | --maintainer=MAINTAINER : Debian package maintainer name 18 | -e EMAIL, --email=EMAIL : Debian package maintainer email 19 | -p PACKAGEPREFIX, 20 | --package-prefix=PACKAGEPREFIX : Debian package name prefix 21 | -u DEBVERSION, 22 | --debian-version=DEBVERSION : Debian package version 23 | -b DEBBUILD, 24 | --debian-build=DEBBUILD : Debian package build 25 | --registry=REGISTRY : Registry for npm install 26 | -v, --version : Show version 27 | 28 | ## Environment 29 | 30 | These environmanet variables are used during the packaging: 31 | 32 | EMAIL="email@address" 33 | DEBFULLNAME="Maintainer Full Name" 34 | 35 | You will need the following Debian packages for the tool to work: 36 | 37 | sudo apt-get install devscripts dh-make 38 | 39 | You will need the following Debian packages to build debs: 40 | 41 | sudo apt-get install debhelper fakeroot dpkg-dev 42 | 43 | ## Install 44 | 45 | You have several options. 46 | 47 | * Install globally from npm repository 48 | 49 | `npm -g install npm2debian` 50 | 51 | * Install locally 52 | 53 | `npm install npm2debian` 54 | 55 | * Install from sources 56 | 57 | ``` 58 | git clone https://github.com/arikon/npm2debian 59 | cd npm2debian 60 | npm install 61 | ``` 62 | 63 | ## Usage examples 64 | 65 | * Simple converting of `bem` package to `npm-bem`: 66 | 67 | `npm2debian bem` 68 | 69 | It will create `npm-bem-` directory with source Debian package describing only one binary package `npm-bem`. 70 | 71 | * To get Debian package with version in its name you should specify `--versioned` options: 72 | 73 | `npm2debian --versioned bem` 74 | 75 | It will create `npm-bem-` directory with source Debian package describing two binary packages: 76 | 77 | * `npm-bem` 78 | * `npm-bem-`, where `` is a package version with dots replaced to dashes 79 | 80 | * To build debs run: 81 | 82 | ``` 83 | cd npm-bem* 84 | dpkg-buildpackage -rfakeroot 85 | ``` 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /README.ru.md: -------------------------------------------------------------------------------- 1 | # npm2debian 2 | **npm2debian** это инструмент командной строки предназначенный для конвертации пакетов из реестра npmjs.org в готовый для сборки Debian пакет. 3 | 4 | ## Обзор 5 | 6 | npm2debian [опции] <имя пакета из реестра NPM> 7 | 8 | ## Опции 9 | 10 | -h, --help : показать подсказку для опций 11 | -o OUTPUT, --output=OUTPUT : изменить директорию с результатом 12 | --versioned : подготовить Debian пакет с указанием версии 13 | --no-package-prefix : не указывать префикс для Debian пакетов 14 | -m MAINTAINER, 15 | --maintainer=MAINTAINER : указать имя сопровождающего Debian пакет 16 | -e EMAIL, --email=EMAIL : указать email сопровождающего Debian пакет 17 | -p PACKAGEPREFIX, 18 | --package-prefix=PACKAGEPREFIX : указать Debian префикс для имени пакета 19 | -u DEBVERSION, 20 | --debian-version=DEBVERSION : указать Debian версию для пакета 21 | -b DEBBUILD, 22 | --debian-build=DEBBUILD : указать Debian package build 23 | --registry=REGISTRY : указать registry для npm install 24 | -v, --version : показать версию инструмента 25 | 26 | ## Окружение 27 | 28 | При работе используются следующие переменные окружения 29 | 30 | EMAIL="Адрес электронной почты" 31 | DEBFULLNAME="Имя и Фамилия сопровождающего пакет" 32 | 33 | Для работы инструмента необходимы следующие Debian пакеты: 34 | 35 | sudo apt-get install devscripts dh-make 36 | 37 | Для сборки сконвертированных пакетов установите следующие Debian пакеты: 38 | 39 | sudo apt-get install debhelper fakeroot dpkg-dev 40 | 41 | ## Установка 42 | 43 | Есть несколько способов установки. 44 | 45 | * В систему вы можете установить утилиту глобально в виде пакета npm 46 | 47 | `npm -g install npm2debian` 48 | 49 | * Локальная установка 50 | 51 | `npm install npm2debian` 52 | 53 | * Установка из исходников 54 | 55 | ``` 56 | git clone https://github.com/arikon/npm2debian 57 | cd npm2debian 58 | npm install 59 | ``` 60 | 61 | ## Примеры использования 62 | 63 | * Конвертирование пакета `bem`: 64 | 65 | `npm2debian bem` 66 | 67 | В результате в директории `npm-bem-` будет создан сорцовый пакет для сборки одного бинарного пакета `npm-bem`. 68 | 69 | * Для создания пакета с версией в имени нужно указать опцию `--versioned`: 70 | 71 | `npm2debian --versioned bem` 72 | 73 | В результате в директории `npm-bem-` будет создан сорцовый пакет для сборки двух бинарных пакетов: 74 | 75 | * `npm-bem` 76 | * `npm-bem-`, где ``, это версия, где вместо точек используются дефисы 77 | 78 | * Сборка конвертированного Debian пакета: 79 | 80 | ``` 81 | cd npm-bem* 82 | dpkg-buildpackage -rfakeroot 83 | ``` 84 | -------------------------------------------------------------------------------- /bin/npm2debian: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../lib/cli').main(); 4 | -------------------------------------------------------------------------------- /debian-npm-ver/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian-npm-ver/control: -------------------------------------------------------------------------------- 1 | Source: #PACKAGE# 2 | Section: misc 3 | Priority: optional 4 | Maintainer: #USERNAME# <#EMAIL#> 5 | Build-Depends: nodejs, debhelper (>= 7.0.52), ${buildDepends}, #BUILD_DEPS# 6 | Standards-Version: #POLICY# 7 | 8 | Package: #PACKAGE# 9 | Architecture: ${arch} 10 | Depends: #PACKAGE#${debianNameSuffix}, ${shlibs:Depends}, ${misc:Depends} 11 | XB-Conductor-Package: #PACKAGE# 12 | Description: ${shortdesc} 13 | ${longdesc} 14 | 15 | Package: #PACKAGE#${debianNameSuffix} 16 | Architecture: ${arch} 17 | Depends: ${depends}, ${shlibs:Depends}, ${misc:Depends} 18 | XB-Conductor-Package: #PACKAGE#- 19 | Description: ${shortdesc} 20 | ${longdesc} 21 | -------------------------------------------------------------------------------- /debian-npm-ver/dirs.in: -------------------------------------------------------------------------------- 1 | usr/lib/node 2 | -------------------------------------------------------------------------------- /debian-npm-ver/install: -------------------------------------------------------------------------------- 1 | ${install} 2 | -------------------------------------------------------------------------------- /debian-npm-ver/links: -------------------------------------------------------------------------------- 1 | usr/lib/node/${pkg}@${ver} usr/lib/node_modules/${pkg} 2 | usr/lib/node/${pkg}@${ver} usr/lib/node/${pkg} 3 | -------------------------------------------------------------------------------- /debian-npm-ver/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | NPM_PACKAGE=${pkg} 4 | NPM_VERSION=${ver} 5 | PACKAGE=${debianName} 6 | PACKAGE_VERSIONED=${debianNameVersioned} 7 | ROOT=./debian/$(PACKAGE) 8 | ROOT_VERSIONED=./debian/$(PACKAGE_VERSIONED) 9 | NODE_PREFIX=$(ROOT)/usr 10 | NODE_PREFIX_VERSIONED=$(ROOT_VERSIONED)/usr 11 | 12 | %: 13 | dh $@ 14 | 15 | override_dh_auto_build: 16 | cp debian/dirs.in debian/$(PACKAGE_VERSIONED).dirs 17 | npm build 18 | npm install --dev 19 | 20 | override_dh_auto_test: 21 | npm test 22 | 23 | override_dh_auto_install: 24 | npm install --global --prefix $(NODE_PREFIX) . 25 | # move module 26 | mv $(NODE_PREFIX)/lib/node_modules/$(NPM_PACKAGE) $(NODE_PREFIX_VERSIONED)/lib/node/$(NPM_PACKAGE)@$(NPM_VERSION) 27 | 28 | clean: 29 | -rm -f debian/$(PACKAGE)-*.dirs 30 | ${cleanCmd} 31 | dh clean 32 | -------------------------------------------------------------------------------- /debian-npm-ver/watch.ex: -------------------------------------------------------------------------------- 1 | # Example watch control file for uscan 2 | # Rename this file to "watch" and then you can run the "uscan" command 3 | # to check for upstream updates and more. 4 | # See uscan(1) for format 5 | 6 | # Compulsory line, this is a version 3 file 7 | version=3 8 | 9 | # Uncomment to examine a Webpage 10 | # 11 | #http://www.example.com/downloads.php #PACKAGE#-(.*)\.tar\.gz 12 | 13 | # Uncomment to examine a Webserver directory 14 | #http://www.example.com/pub/#PACKAGE#-(.*)\.tar\.gz 15 | 16 | # Uncommment to examine a FTP server 17 | #ftp://ftp.example.com/pub/#PACKAGE#-(.*)\.tar\.gz debian uupdate 18 | 19 | # Uncomment to find new files on sourceforge, for devscripts >= 2.9 20 | # http://sf.net/#PACKAGE#/#PACKAGE#-(.*)\.tar\.gz 21 | 22 | 23 | -------------------------------------------------------------------------------- /debian-npm/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian-npm/control: -------------------------------------------------------------------------------- 1 | Source: #PACKAGE# 2 | Section: misc 3 | Priority: optional 4 | Maintainer: #USERNAME# <#EMAIL#> 5 | Build-Depends: nodejs, debhelper (>= 7.0.52), ${buildDepends}, #BUILD_DEPS# 6 | Standards-Version: #POLICY# 7 | 8 | Package: #PACKAGE# 9 | Architecture: ${arch} 10 | Depends: ${depends}, ${shlibs:Depends}, ${misc:Depends} 11 | Description: ${shortdesc} 12 | ${longdesc} 13 | -------------------------------------------------------------------------------- /debian-npm/dirs.in: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/lib/node 3 | usr/lib/node_modules 4 | usr/share 5 | -------------------------------------------------------------------------------- /debian-npm/install: -------------------------------------------------------------------------------- 1 | ${install} 2 | -------------------------------------------------------------------------------- /debian-npm/links: -------------------------------------------------------------------------------- 1 | usr/lib/node_modules/${pkg} usr/lib/node/${pkg} 2 | -------------------------------------------------------------------------------- /debian-npm/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | NODE_PREFIX=debian/${debianName}/usr 4 | 5 | %: 6 | dh $@ 7 | 8 | override_dh_auto_build: 9 | npm build 10 | npm install --dev 11 | 12 | override_dh_auto_test: 13 | npm test 14 | 15 | override_dh_auto_install: 16 | npm install --global --prefix $(NODE_PREFIX) . 17 | 18 | clean: 19 | ${cleanCmd} 20 | dh clean 21 | -------------------------------------------------------------------------------- /debian-npm/watch.ex: -------------------------------------------------------------------------------- 1 | # Example watch control file for uscan 2 | # Rename this file to "watch" and then you can run the "uscan" command 3 | # to check for upstream updates and more. 4 | # See uscan(1) for format 5 | 6 | # Compulsory line, this is a version 3 file 7 | version=3 8 | 9 | # Uncomment to examine a Webpage 10 | # 11 | #http://www.example.com/downloads.php #PACKAGE#-(.*)\.tar\.gz 12 | 13 | # Uncomment to examine a Webserver directory 14 | #http://www.example.com/pub/#PACKAGE#-(.*)\.tar\.gz 15 | 16 | # Uncommment to examine a FTP server 17 | #ftp://ftp.example.com/pub/#PACKAGE#-(.*)\.tar\.gz debian uupdate 18 | 19 | # Uncomment to find new files on sourceforge, for devscripts >= 2.9 20 | # http://sf.net/#PACKAGE#/#PACKAGE#-(.*)\.tar\.gz 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'), 2 | QFS = require('q-io/fs'), 3 | CP = require('child_process'), 4 | FS = require('fs'), 5 | PATH = require('path'), 6 | SYS = require('util'), 7 | NPM = require('npm'), 8 | SEMVER = require('semver'); 9 | 10 | BIN = { 11 | 'debchange': 'debchange', 12 | 'dh_make': 'dh_make' 13 | }; 14 | 15 | exports.main = function () { 16 | 17 | var pkgJson = JSON.parse(FS.readFileSync(PATH.resolve(__dirname, '../package.json'))); 18 | 19 | require('coa').Cmd() 20 | .name(PATH.basename(process.argv[1])) 21 | .title(pkgJson.description) 22 | .helpful() 23 | .opt() 24 | .name('output').title('Output directory') 25 | .short('o').long('output') 26 | .def(process.cwd()) 27 | .end() 28 | .opt() 29 | .name('versioned').title('Build versioned debian package') 30 | .long('versioned') 31 | .flag() 32 | .end() 33 | .opt() 34 | .name('maintainer').title('Debian package maintainer name') 35 | .short('m').long('maintainer') 36 | .def(process.env.DEBFULLNAME) 37 | .end() 38 | .opt() 39 | .name('email').title('Debian package maintainer email') 40 | .short('e').long('email') 41 | .def(process.env.EMAIL) 42 | .end() 43 | .opt() 44 | .name('packagePrefix').title('Debian package name prefix') 45 | .short('p').long('package-prefix') 46 | .def('npm-') 47 | .end() 48 | .opt() 49 | .name('noPackagePrefix').title('Do not add prefix to Debian package name') 50 | .long('no-package-prefix') 51 | .flag() 52 | .end() 53 | .opt() 54 | .name('debVersion').title('Debian package version') 55 | .short('u').long('debian-version') 56 | .end() 57 | .opt() 58 | .name('debBuild').title('Debian package build') 59 | .short('b').long('debian-build') 60 | .def('1') 61 | .end() 62 | .opt() 63 | .name('version').title('Show version') 64 | .short('v').long('version') 65 | .flag() 66 | .only() 67 | .act(function() { 68 | return pkgJson.version; 69 | }) 70 | .end() 71 | .arg() 72 | .name('pkg').title('Package') 73 | .arr() 74 | .req() 75 | .end() 76 | .opt() 77 | .name('registry').title('npm registry address') 78 | .long('registry') 79 | .end() 80 | .completable() 81 | .act(function(opts, args) { 82 | 83 | return loadConf({cache: PATH.resolve('.cache'), registry: opts.registry}) 84 | .then(function() { 85 | console.log('versioned = %s', opts.versioned); 86 | console.log('bin = %s', NPM.bin); 87 | console.log('dir = %s', NPM.dir); 88 | console.log('cache = %s', NPM.cache); 89 | console.log('tmp = %s', NPM.tmp); 90 | console.log('binaries = %s', SYS.inspect(BIN)); 91 | 92 | return args.pkg.reduce(function(done, pkg) { 93 | return Q.all([done, debianize(pkg, opts)]).get(0); 94 | }, undefined); 95 | }); 96 | 97 | }) 98 | .run(); 99 | 100 | }; 101 | 102 | var loadConf = function(conf) { 103 | var d = Q.defer(); 104 | NPM.load(conf, function(err) { 105 | if(err) { 106 | d.reject(err); 107 | return; 108 | } 109 | if(conf.registry) { 110 | NPM.config.set('registry', conf.registry); // npm doesn't set registry from conf 111 | } 112 | d.resolve(); 113 | }); 114 | return d.promise; 115 | }; 116 | 117 | var npmInstall = function(where, pkg) { 118 | if(!pkg) { 119 | pkg = where; 120 | where = null; 121 | } 122 | console.log('npmInstall: %s, %j', where, pkg); 123 | var d = Q.defer(); 124 | NPM.commands.install(where, pkg, function(err, data) { 125 | err? d.reject(err) : d.resolve(data); 126 | }); 127 | return d.promise; 128 | }; 129 | 130 | var cacheAdd = function(pkg) { 131 | console.log('cacheAdd: %s', pkg); 132 | var d = Q.defer(); 133 | NPM.commands.cache.add(pkg, function(err, data) { 134 | err? d.reject(err) : d.resolve(data); 135 | }); 136 | return d.promise; 137 | }; 138 | 139 | var cacheRead = function(pkg, ver, forceBypass) { 140 | console.log('cacheRead: %s-%s', pkg, ver); 141 | var d = Q.defer(); 142 | NPM.commands.cache.read(pkg, ver, forceBypass, function(err, data) { 143 | err? d.reject(err) : d.resolve(data); 144 | }); 145 | return d.promise; 146 | }; 147 | 148 | var cacheUnpack = function(pkg, ver, targetPath) { 149 | console.log('cacheUnpack: %s-%s', pkg, ver); 150 | var d = Q.defer(); 151 | NPM.commands.cache.unpack(pkg, ver, targetPath, function(err) { 152 | err? d.reject(err) : d.resolve(); 153 | }); 154 | return d.promise; 155 | }; 156 | 157 | var debianize = function(pkg, opts) { 158 | console.log('debianize: %s', pkg); 159 | return cacheAdd(pkg) 160 | .then(function(data) { 161 | return makeSourcePackage(data.name, data.version, opts); 162 | }); 163 | }; 164 | 165 | var makeSourcePackage = function(pkg, ver, opts) { 166 | var ctx = {}; 167 | 168 | // populate context from args and opts 169 | ctx.pkg = pkg; 170 | ctx.ver = ver; 171 | ctx.versioned = opts.versioned; 172 | ctx.arch = 'all'; // TODO: support 'all' and 'any' 173 | ctx.maintainer = opts.maintainer; 174 | ctx.email = opts.email; 175 | ctx.debianNamePrefix = opts.noPackagePrefix ? '' : opts.packagePrefix; 176 | ctx.debianVersionBuild = opts.debBuild; 177 | ctx.debianVersion = opts.debVersion || ver + '-' + ctx.debianVersionBuild; 178 | ctx.debianNameSuffix = '-' + ver.replace(/\./g, '-'); 179 | ctx.debianName = ctx.debianNamePrefix + pkg; 180 | ctx.debianNameVersioned = ctx.debianName + ctx.debianNameSuffix; 181 | 182 | var debianPackageDir = PATH.join(opts.output, ctx.debianName + '-' + ver), 183 | debianDir = PATH.join(debianPackageDir, 'debian'); 184 | 185 | return QFS.exists(debianPackageDir) 186 | .then(function(exists) { 187 | if (exists) { 188 | return rimraf(debianPackageDir); 189 | } 190 | }) 191 | .then(function() { 192 | 193 | return cacheUnpack(pkg, ver, debianPackageDir) 194 | .then(function() { 195 | return npmInstall(debianPackageDir, []); 196 | }) 197 | .then(function() { 198 | return cacheRead(pkg, ver); 199 | }) 200 | .then(function(packageData) { 201 | 202 | ctx.packageData = packageData; 203 | ctx.shortdesc = packageData.description || ''; 204 | ctx.longdesc = 'This is a debianized npm package'; 205 | 206 | var cleanPackages = [], 207 | deps = packageData.dependencies || {}, 208 | devDeps = packageData.devDependencies || {}, 209 | bundleDeps = packageData.bundledDependencies || [], 210 | filter = function(key) { 211 | return bundleDeps.indexOf(key) === -1; 212 | }; 213 | 214 | console.log('deps = %j', deps); 215 | console.log('devDeps = %j', devDeps); 216 | console.log('bundleDeps = %j', bundleDeps); 217 | 218 | cleanPackages = cleanPackages.concat(filterObjectKeys(deps, filter), filterObjectKeys(devDeps, filter)); 219 | console.log('cleanPackages = %j', cleanPackages); 220 | if (cleanPackages.length) ctx.cleanCmd = 'npm uninstall ' + cleanPackages.join(' '); 221 | 222 | var nodeVer, npmVer; 223 | try { 224 | nodeVer = packageData.engines.node; 225 | } catch(ignore) {} 226 | try { 227 | npmVer = packageData.engines.npm; 228 | } catch(ignore) {} 229 | 230 | ctx.depends = semverToDebian('nodejs', nodeVer); 231 | ctx.buildDepends = semverToDebian('npm', npmVer); 232 | 233 | }) 234 | .then(function() { 235 | return dh_make(debianPackageDir, ctx); 236 | }) 237 | .then(function() { 238 | return dch(debianPackageDir, ctx.debianName, ctx.debianVersion, 'Release of ' + pkg + ' ' + ver); 239 | }) 240 | .then(function() { 241 | var n2d = ctx.packageData.npm2debian; 242 | if(n2d && n2d['bash-completion']) { 243 | return generateBashCompletion(debianPackageDir, n2d['bash-completion'], ctx); 244 | } 245 | }) 246 | .then(function() { 247 | return Q.all([ 248 | tplDebianFile(PATH.join(debianDir, 'control'), ctx), 249 | tplDebianFile(PATH.join(debianDir, 'rules'), ctx), 250 | tplDebianFile(PATH.join(debianDir, 'install'), ctx), 251 | tplDebianFile(PATH.join(debianDir, 'links'), ctx) 252 | ]); 253 | }); 254 | 255 | }); 256 | }; 257 | 258 | var filterObjectKeys = function(obj, cb) { 259 | cb = cb || function() { 260 | return true; 261 | }; 262 | var keys = []; 263 | for (var key in obj) { 264 | if (!obj.hasOwnProperty(key) || !cb(key, obj)) continue; 265 | keys.push(key); 266 | } 267 | return keys; 268 | }; 269 | 270 | var generateBashCompletion = function(dir, comps, ctx) { 271 | // generate debian/install for etc/bash_completion.d/* 272 | ctx.install = 'etc/bash_completion.d/* etc/bash_completion.d'; 273 | 274 | var compPath = PATH.resolve(dir, 'etc/bash_completion.d'); 275 | 276 | // create etc/bash_completion.d dir 277 | return mkdir(compPath) 278 | .then(function() { 279 | // generate completions scripts to etc/bash_completion.d 280 | var done; 281 | for (var bin in comps) { 282 | done = Q.all([done, saveBashCompletionScript(dir, PATH.join(compPath, bin), comps[bin])]).get(0); 283 | } 284 | return done; 285 | }); 286 | }; 287 | 288 | var saveBashCompletionScript = function(dir, path, comp) { 289 | if(!comp.script) { 290 | return Q.resolve(); 291 | } 292 | 293 | return Q.fcall(function() { 294 | var d = Q.defer(), 295 | opts = { cwd: dir, env: process.env }; 296 | 297 | CP.exec(comp.script, opts, function(err, stdout, stderr) { 298 | err? d.reject(err) : d.resolve(stdout); 299 | }); 300 | 301 | console.log(comp.script); 302 | 303 | return d.promise; 304 | }) 305 | .then(function(content) { 306 | return QFS.write(path, content, { charset: 'utf8' }); 307 | }); 308 | }; 309 | 310 | var dh_make = function(dir, ctx) { 311 | var d = Q.defer(), 312 | tplDir = ctx.versioned? 'debian-npm-ver' : 'debian-npm', 313 | cmd = [ 314 | BIN.dh_make, 315 | //'--cdbs', 316 | '--defaultless', 317 | '--templates', PATH.resolve(__dirname, '..', tplDir), 318 | '--packagename', ctx.debianName, 319 | //'--copyright', 'gpl', // TODO 320 | '--createorig', 321 | '--file', PATH.resolve(NPM.cache, ctx.pkg, ctx.ver, 'package.tgz') 322 | ].join(' '), 323 | opts = { cwd: dir, env: process.env }; 324 | 325 | console.log(cmd); 326 | 327 | var child = CP.exec(cmd, opts, function(err, stdout, stderr) { 328 | err? d.reject(err) : d.resolve(); 329 | }); 330 | child.stdin.write('\n'); 331 | 332 | return d.promise; 333 | }; 334 | 335 | var dch = function(dir, pkg, ver, text) { 336 | var d = Q.defer(), 337 | cmd = [ 338 | BIN.debchange, 339 | '--create', 340 | '--empty', 341 | '--package', pkg, 342 | '--newversion', ver, 343 | '--distribution', 'unstable', 344 | '--force-distribution', 345 | '"' + text + '"' 346 | ].join(' '), 347 | opts = { cwd: dir, env: process.env }; 348 | 349 | console.log(cmd); 350 | 351 | CP.exec(cmd, opts, function(err, stdout, stderr) { 352 | err? d.reject(err) : d.resolve(); 353 | }); 354 | 355 | return d.promise; 356 | }; 357 | 358 | var rimraf = function(path) { 359 | var d = Q.defer(); 360 | require('rimraf')(path, function(err) { 361 | err? d.reject(err) : d.resolve(); 362 | }); 363 | return d.promise; 364 | }; 365 | 366 | var mkdir = function(ensure, mode, uid, gid, noChmod) { 367 | var d = Q.defer(); 368 | require('npm/lib/utils/mkdir-p')(ensure, mode || '0777', uid, gid, noChmod, function(err) { 369 | err? d.reject(err) : d.resolve(); 370 | }); 371 | return d.promise; 372 | }; 373 | 374 | var tplDebianFile = function(path, ctx) { 375 | return Q.when(QFS.read(path, { charset: 'utf8' }), function(tpl) { 376 | console.log('tplDebianFile: %s', path); 377 | return QFS.write(path, parseTemplate(tpl, ctx), { charset: 'utf8' }); 378 | }); 379 | }; 380 | 381 | var parseTemplate = function(template, vars) { 382 | return (Array.isArray(template)? template.join('\n') + '\n' : template) 383 | .replace(/\${\s*([^\s:}]*)\s*}/gi, function(s, varName){ 384 | return (vars || {})[varName] || ''; 385 | }); 386 | }; 387 | 388 | var semverToDebian = function(pkg, ver) { 389 | if(!ver) return pkg; 390 | 391 | var comparators = SEMVER.Range(ver, true).set, 392 | deps = []; 393 | 394 | comparators.forEach(function(comp) { 395 | 396 | comp.forEach(function(edge) { 397 | // strip leading "-0" 398 | edge = edge.value.replace(/-0$/, ''); 399 | 400 | if(!edge) { 401 | deps.push(pkg); 402 | } else { 403 | edge = edge 404 | .replace(/^(\d)/, '= $1') 405 | .replace(/^(<|>)(\d)/, '$1$1 $2') 406 | .replace(/^(>=|<=)/, '$1 '); 407 | deps.push(pkg + ' (' + edge + ')'); 408 | } 409 | }); 410 | }); 411 | 412 | return deps.join(' | '); 413 | }; 414 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm2debian", 3 | "description": "Utility to convert npm packages to Debian packages", 4 | "version": "0.3.1", 5 | "author": "Sergey Belov (http://github.com/arikon)", 6 | "directories": { 7 | "lib": "./lib" 8 | }, 9 | "bin": { 10 | "npm2debian": "./bin/npm2debian" 11 | }, 12 | "npm2debian": { 13 | "bash-completion": { 14 | "npm2debian": { 15 | "script": "./bin/npm2debian completion" 16 | } 17 | } 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/arikon/npm2debian.git" 22 | }, 23 | "dependencies": { 24 | "coa": "~0.4.0", 25 | "npm": "~1.3.15", 26 | "rimraf": "~2.2.2", 27 | "semver": "~2.2.1", 28 | "q": "~0.9.7", 29 | "q-io": "~1.10.6" 30 | }, 31 | "engines": { 32 | "node": ">=0.8.0 <=0.11.0" 33 | }, 34 | "devDependencies": {}, 35 | "optionalDependencies": {} 36 | } 37 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var SEMVER = require('semver'); 2 | 3 | var parseRange = function(range) { 4 | return SEMVER.toComparators(SEMVER.replaceStars(range.trim())); 5 | }; 6 | 7 | var semverToDebian = function(pkg, ver) { 8 | if(!ver) return pkg; 9 | 10 | var ranges = parseRange(ver), 11 | deps = []; 12 | 13 | ranges.forEach(function(range) { 14 | range.forEach(function(edge) { 15 | if(!edge) { 16 | deps.push(pkg); 17 | } else { 18 | edge = edge 19 | .replace(/^(\d)/, '= $1') 20 | .replace(/^(<|>)(\d)/, '$1$1 $2') 21 | .replace(/^(>=|<=)/, '$1 '); 22 | deps.push(pkg + ' (' + edge + ')'); 23 | } 24 | }); 25 | }); 26 | 27 | return deps.join(' | '); 28 | }; 29 | 30 | console.log(semverToDebian('nodejs', '*')); 31 | console.log(semverToDebian('nodejs', '0.4.12')); 32 | console.log(semverToDebian('nodejs', '~0.4.0')); 33 | console.log(semverToDebian('nodejs', '0.4')); 34 | console.log(semverToDebian('nodejs', '0.4 || 0.5 || 0.6')); 35 | console.log(semverToDebian('nodejs', '=0.4')); 36 | console.log(semverToDebian('nodejs', '>=0.4.0 <0.7.0')); 37 | console.log(semverToDebian('nodejs', '0.x >=0.0.4')); 38 | --------------------------------------------------------------------------------