├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── autogypi ├── package.json ├── src ├── autogypi.ts ├── cli.ts └── resolve.d.ts ├── tsconfig.json ├── tslint.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.js 3 | *.d.ts 4 | *.log.* 5 | *.log 6 | *.tgz 7 | 8 | !src/*.d.ts 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | src/ 3 | .travis.yml 4 | *.log.* 5 | *.log 6 | *.tgz 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "6.0" 5 | - "5.6" 6 | - "4.3" 7 | - "0.12" 8 | 9 | install: npm link 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 BusFaster Ltd 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | autogypi 2 | ======== 3 | 4 | [![build status](https://travis-ci.org/charto/autogypi.svg?branch=master)](http://travis-ci.org/charto/autogypi) 5 | [![dependency status](https://david-dm.org/charto/autogypi.svg)](https://david-dm.org/charto/autogypi) 6 | [![npm version](https://img.shields.io/npm/v/autogypi.svg)](https://www.npmjs.com/package/autogypi) 7 | 8 | `autogypi` handles issues with C++ libraries published on npm. 9 | It generates required compiler and `node-gyp` options for you and works great 10 | with [`nbind`](https://github.com/charto/nbind#readme). 11 | 12 | `node-gyp` is very good at fixing relative paths between `.gypi` files 13 | in different locations, but it cannot automatically find other npm packages, 14 | which may have been installed globally or in a `node_modules` directory 15 | higher up in the directory tree or hidden inside another package. 16 | `autogypi` deals with them. 17 | 18 | Features 19 | ======== 20 | 21 | - Initialize configuration for a `node-gyp` -based project. 22 | - Generate C++ compiler options. 23 | - Guess include directories to use headers from other packages. 24 | - Include additional `.gypi` files required by other packages. 25 | 26 | Usage 27 | ===== 28 | 29 | Installation 30 | ------------ 31 | 32 | Add in the `scripts` section of your `package.json`: 33 | 34 | ```json 35 | "scripts": { 36 | "autogypi": "autogypi", 37 | "node-gyp": "node-gyp", 38 | 39 | "install": "autogypi && node-gyp configure build" 40 | } 41 | ``` 42 | 43 | Then run the commands: 44 | 45 | ```bash 46 | npm install --save autogypi 47 | ``` 48 | 49 | Configuring `node-gyp` 50 | ---------------------- 51 | 52 | You should add `auto-top.gypi` in the in the `includes` section 53 | at the top level of your `binding.gyp` file and `auto.gypi` in the `includes` 54 | section of each target inside. 55 | 56 | If you don't have a `binding.gyp` file yet, you can create one now with the 57 | required changes already made. For example: 58 | 59 | ```bash 60 | npm run -- autogypi --init-gyp -p nbind -s example.cc 61 | ``` 62 | 63 | Replace `example.cc` with the name of your C++ source file. 64 | You can add multiple `-s` options, one for each source file. 65 | 66 | The `-p nbind` option means the C++ code uses a package called 67 | [`nbind`](https://github.com/charto/nbind#readme). 68 | Multiple `-p` options can be added to add any other packages 69 | compatible with `autogypi`. 70 | 71 | The above command creates two files with contents: 72 | 73 | **`binding.gyp`** 74 | 75 | ```json 76 | { 77 | "targets": [ 78 | { 79 | "includes": [ 80 | "auto.gypi" 81 | ], 82 | "sources": [ 83 | "example.cc" 84 | ] 85 | } 86 | ], 87 | "includes": [ 88 | "auto-top.gypi" 89 | ] 90 | } 91 | ``` 92 | 93 | **`autogypi.json`** 94 | 95 | ```json 96 | { 97 | "dependencies": [ 98 | "nbind" 99 | ], 100 | "includes": [] 101 | } 102 | ``` 103 | 104 | It also prints an error if the packages you listed as dependencies are missing. 105 | For example you can install `nbind` and run `autogypi` again: 106 | 107 | ```bash 108 | npm install --save nbind 109 | npm run autogypi 110 | ``` 111 | 112 | Compiling your project 113 | ---------------------- 114 | 115 | Call `autogypi` and `node-gyp` from the install script in your 116 | `package.json` file, for example like 117 | `autogypi && node-gyp configure build` 118 | or from the command line: 119 | `npm run autogypi && npm run node-gyp configure build` 120 | 121 | `autogypi` generates two `.gypi` files according to its configuration. 122 | For example with only `nbind` as a dependency they look like: 123 | 124 | **`auto-top.gypi`** 125 | 126 | ```json 127 | { 128 | "includes": [ 129 | "node_modules/nbind/src/nbind-common.gypi" 130 | ] 131 | } 132 | ``` 133 | 134 | **`auto.gypi`** 135 | 136 | ```json 137 | { 138 | "include_dirs": [ 139 | "node_modules/nbind/node_modules/nan" 140 | ], 141 | "includes": [ 142 | "node_modules/nbind/src/nbind.gypi" 143 | ] 144 | } 145 | ``` 146 | 147 | Publishing a C++ library on npm 148 | ------------------------------- 149 | 150 | Packages should include an `autogypi.json` file in their root directory 151 | if they require or are intended to be used by other modules. 152 | They should list any .gypi files of their own that are required to compile 153 | or use the module. For example: 154 | 155 | ```json 156 | { 157 | "dependencies": [ 158 | "nan" 159 | ], 160 | "includes": [ 161 | "example.gypi" 162 | ] 163 | } 164 | ``` 165 | 166 | The `example.gypi` file would then contain any gyp settings 167 | required to successfully compile and include it in other packages. 168 | 169 | Modules without any `autogypi.json` file get their root directory 170 | added to `include_dirs`. This is enough to successfully use the `nan` module. 171 | More heuristics may be added later if needed. 172 | 173 | Command line options 174 | ==================== 175 | 176 | Run `npm run -- autogypi --help` to see the command line options: 177 | 178 | ``` 179 | Usage: autogypi [options] 180 | 181 | Generate node-gyp dependency files. 182 | 183 | Options: 184 | 185 | -h, --help output usage information 186 | -V, --version output the version number 187 | -r, --root root path for config files, default is shell working directory 188 | -c, --config config file, default autogypi.json 189 | -o, --output per-target gypi file to create, default auto.gypi 190 | -t, --output-top top-level gypi file to create, default auto-top.gypi 191 | -T, --no-output-top omit top-level gypi file 192 | -p, --package add dependency on another npm package 193 | -I, --include-dir add include directory for header files 194 | --save [flag] save changes to config file 195 | --init-gyp [path] create gyp file (default binding.gyp, implies --save) with options: 196 | -s, --source - add C or C++ source file 197 | ``` 198 | 199 | Renaming `autogypi.json`, `auto.gypi` and `auto-top.gypi` using the relevant 200 | command line parameters will affect generating the `.gypi` files and also 201 | the contents of any `binding.gyp` generated using the `--init-gyp` option. 202 | 203 | API 204 | === 205 | Docs generated using [`docts`](https://github.com/charto/docts) 206 | > 207 | > 208 | > ### Interface [`AutogypiConfig`](#api-AutogypiConfig) 209 | > Format of autogypi.json files published in Node.js modules. 210 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L36-L47) 211 | > 212 | > Properties: 213 | > > **.dependencies**? string[] 214 | > >  List of required Node.js modules. 215 | > > **.includes**? string[] 216 | > >  Additional gypi files to include inside relevant targets. 217 | > > **.topIncludes**? string[] 218 | > >  Additional gypi files to include at top level. 219 | > > **.output**? string 220 | > >  Path to auto.gypi to generate. 221 | > > **.outputTop**? string 222 | > >  Path to auto-top.gypi to generate. 223 | > 224 | > 225 | > ### Interface [`BindingConfig`](#api-BindingConfig) 226 | > Options for generating an initial binding.gyp file. 227 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L12-L21) 228 | > 229 | > Properties: 230 | > > **.basePath** string 231 | > >  Directory where the binding.gyp will be stored. 232 | > > **.outputPath** string 233 | > >  Absolute path to generated auto.gypi to include in default target. 234 | > > **.outputTopPath** string 235 | > >  Absolute path to generated auto-top.gypi to include at top level. 236 | > > **.sourceList** string[] 237 | > >  List of absolute paths to C/C++ source files to compile. 238 | > 239 | > 240 | > ### Interface [`GenerateOptions`](#api-GenerateOptions) 241 | > General options for generating gypi files. 242 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L25-L32) 243 | > 244 | > Properties: 245 | > > **.configPath** string 246 | > >  Absolute path to autogypi.json. 247 | > > **.outputPath** string 248 | > >  Absolute path to auto.gypi to generate. 249 | > > **.outputTopPath** string 250 | > >  Absolute path to auto-top.gypi to generate. 251 | > 252 | > 253 | > ### Function [`generate`](#api-generate) 254 | > Write auto.gypi and auto-top.gypi files according to config. 255 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L188-L216) 256 | > > **generate( )** Bluebird<{}[]> [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L188-L216) 257 | > >  ▪ opts [GenerateOptions](#api-GenerateOptions) 258 | > >  ▪ config [AutogypiConfig](#api-AutogypiConfig) Contents of autogypi.json. 259 | > 260 | > 261 | > ### Function [`initGyp`](#api-initGyp) 262 | > Return an object with contents for an initial binding.gyp file. 263 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L220-L241) 264 | > > **initGyp( )** any [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L220-L241) 265 | > >  ▪ opts [BindingConfig](#api-BindingConfig) 266 | > 267 | > 268 | > ### Function [`writeJson`](#api-writeJson) 269 | > Save pretty-printed JSON object to a file or print an appropriate error. 270 | > Source code: [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L62-L84) 271 | > > **writeJson( )** Bluebird<{}> [`<>`](http://github.com/charto/autogypi/blob/cc6e9d1/src/autogypi.ts#L62-L84) 272 | > >  ▪ outputPath string 273 | > >  ▪ json any 274 | > >  ▫ name? string 275 | > >  ▫ header? string 276 | 277 | License 278 | ======= 279 | 280 | [The MIT License](https://raw.githubusercontent.com/charto/autogypi/master/LICENSE) 281 | Copyright (c) 2015-2016 BusFaster Ltd 282 | -------------------------------------------------------------------------------- /autogypi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('./dist/cli.js'); 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "autogypi", 3 | "version": "0.2.2", 4 | "description": "Autogypi handles dependencies for node-gyp projects.", 5 | "main": "dist/autogypi.js", 6 | "typings": "dist/autogypi.d.ts", 7 | "bin": { 8 | "autogypi": "./autogypi" 9 | }, 10 | "scripts": { 11 | "tsc": "tsc", 12 | "docts": "docts", 13 | "typings": "typings", 14 | 15 | "lint": "tslint src/autogypi.ts src/cli.ts", 16 | "prepublish": "npm run lint && typings install && tsc", 17 | "test": "node autogypi --help" 18 | }, 19 | "author": "Juha Järvi", 20 | "license": "MIT", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/charto/autogypi.git" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/charto/autogypi/issues" 27 | }, 28 | "homepage": "https://github.com/charto/autogypi#readme", 29 | "dependencies": { 30 | "bluebird": "^3.4.0", 31 | "commander": "~2.9.0", 32 | "resolve": "~1.1.7" 33 | }, 34 | "devDependencies": { 35 | "docts": "~0.1.0", 36 | "tslint": "^3.10.2", 37 | "typescript": "^1.8.10", 38 | "typings": "~0.8.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/autogypi.ts: -------------------------------------------------------------------------------- 1 | // This file is part of autogypi, copyright (C) 2015-2016 BusFaster Ltd. 2 | // Released under the MIT license, see LICENSE. 3 | 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | 7 | import * as Promise from 'bluebird'; 8 | import * as resolve from 'resolve'; 9 | 10 | /** Options for generating an initial binding.gyp file. */ 11 | 12 | export interface BindingConfig { 13 | /** Directory where the binding.gyp will be stored. */ 14 | basePath: string; 15 | /** Absolute path to generated auto.gypi to include in default target. */ 16 | outputPath: string; 17 | /** Absolute path to generated auto-top.gypi to include at top level. */ 18 | outputTopPath: string; 19 | /** List of absolute paths to C/C++ source files to compile. */ 20 | sourceList: string[]; 21 | } 22 | 23 | /** General options for generating gypi files. */ 24 | 25 | export interface GenerateOptions { 26 | /** Absolute path to autogypi.json. */ 27 | configPath: string; 28 | /** Absolute path to auto.gypi to generate. */ 29 | outputPath: string; 30 | /** Absolute path to auto-top.gypi to generate. */ 31 | outputTopPath: string; 32 | } 33 | 34 | /** Format of autogypi.json files published in Node.js modules. */ 35 | 36 | export interface AutogypiConfig { 37 | /** List of required Node.js modules. */ 38 | dependencies?: string[]; 39 | /** Additional gypi files to include inside relevant targets. */ 40 | includes?: string[]; 41 | /** Additional gypi files to include at top level. */ 42 | topIncludes?: string[]; 43 | /** Path to auto.gypi to generate. */ 44 | output?: string; 45 | /** Path to auto-top.gypi to generate. */ 46 | outputTop?: string; 47 | } 48 | 49 | interface Gypi { 50 | [ key: string ]: any; 51 | 'include_dirs'?: string[]; 52 | includes?: string[]; 53 | } 54 | 55 | interface GypiPair { 56 | gypi?: Gypi; 57 | gypiTop?: Gypi; 58 | } 59 | 60 | /** Save pretty-printed JSON object to a file. */ 61 | 62 | export function writeJson(outputPath: string, json: any, name?: string, header?: string) { 63 | const writeFile = Promise.promisify( 64 | fs.writeFile as ( 65 | path: string, 66 | data: string, 67 | options: any, 68 | cb: (err: NodeJS.ErrnoException) => void 69 | ) => void 70 | ); 71 | 72 | return(writeFile( 73 | outputPath, 74 | ( 75 | (header || '') + 76 | JSON.stringify(json, null, 1).replace( 77 | /\n +/g, 78 | (indent: string) => indent.replace(/ /g, '\t') 79 | ) + 80 | '\n' 81 | ), 82 | { encoding: 'utf-8' } 83 | )); 84 | } 85 | 86 | function parseConfig(configPath: string, config?: AutogypiConfig): Promise { 87 | const basePath = path.dirname(configPath); 88 | 89 | if(!config) { 90 | try { 91 | config = require(configPath); 92 | } catch(err) { 93 | return(Promise.reject(err)); 94 | } 95 | } 96 | 97 | function resolveFile(relativePath: string) { 98 | return(path.resolve(basePath, relativePath)); 99 | } 100 | 101 | // Get list of gypi options for required Node.js modules. 102 | 103 | const dependenciesDone = Promise.map(config.dependencies || [], (dep: string) => 104 | // Find package.json file of required module. 105 | 106 | Promise.promisify(resolve)( 107 | dep, 108 | { 109 | basedir: basePath, 110 | packageFilter: (json: any) => { 111 | json.main = 'package.json'; 112 | return(json); 113 | } 114 | } 115 | ).then((entry: string) => 116 | // Parse possible autogypi.json file specifying how to include the module. 117 | 118 | parseConfig( 119 | path.resolve(path.dirname(entry), 'autogypi.json') 120 | ).catch((err: any) => { 121 | // No configuration file found, just add the root directory to include paths. 122 | // This is enough for nan. 123 | 124 | const pair: GypiPair = { 125 | gypi: { 126 | 'include_dirs': [ path.dirname(entry) ] 127 | } 128 | }; 129 | 130 | return(pair); 131 | }) 132 | ) 133 | ); 134 | 135 | const parseDone = dependenciesDone.then((gypiList: GypiPair[]) => { 136 | const gypi: Gypi = {}; 137 | const gypiTop: Gypi = {}; 138 | 139 | // Flatten list of gypi options for required modules, 140 | // concatenating all lists of files with matching keys. 141 | 142 | for(let sub of gypiList) { 143 | for(let key of Object.keys(sub.gypi || {})) { 144 | gypi[key] = (gypi[key] || []).concat(sub.gypi[key]); 145 | } 146 | 147 | for(let key of Object.keys(sub.gypiTop || {})) { 148 | gypiTop[key] = (gypiTop[key] || []).concat(sub.gypiTop[key]); 149 | } 150 | } 151 | 152 | // Add options for this module. Make all paths absolute. 153 | 154 | if(config.includes) { 155 | gypi.includes = (gypi.includes || []).concat(config.includes.map(resolveFile)); 156 | } 157 | 158 | if(config.topIncludes) { 159 | gypiTop.includes = (gypiTop.includes || []).concat(config.topIncludes.map(resolveFile)); 160 | } 161 | 162 | const pair: GypiPair = { 163 | gypi: gypi, 164 | gypiTop: gypiTop 165 | }; 166 | 167 | return(pair); 168 | }); 169 | 170 | return(parseDone); 171 | } 172 | 173 | function relativize(outputPath: string, gypi: Gypi) { 174 | function relativizeList(pathList: string[]) { 175 | return(pathList.map((absolutePath: string) => 176 | path.relative(outputPath, absolutePath) 177 | )); 178 | } 179 | 180 | for(let key of ['include_dirs', 'includes']) { 181 | if(gypi[key]) gypi[key] = relativizeList(gypi[key]); 182 | } 183 | } 184 | 185 | /** Write auto.gypi and auto-top.gypi files according to config. 186 | * @param config Contents of autogypi.json. */ 187 | 188 | export function generate(opts: GenerateOptions, config: AutogypiConfig) { 189 | const parseDone = parseConfig(opts.configPath, config); 190 | 191 | const generateDone = parseDone.then((result: GypiPair) => { 192 | const header = [ 193 | '# Automatically generated file. Edits will be lost.', 194 | '# Based on: ' + path.relative(path.dirname(opts.outputPath), opts.configPath), 195 | '', '' 196 | ].join('\n'); 197 | 198 | // Serialize generated .gypi contents with relative paths to output JSON files. 199 | relativize(path.dirname(opts.outputPath), result.gypi); 200 | 201 | const writeTasks = [ 202 | writeJson(opts.outputPath, result.gypi, 'gypi', header) 203 | ]; 204 | 205 | if(opts.outputTopPath) { 206 | relativize(path.dirname(opts.outputTopPath), result.gypiTop); 207 | writeTasks.push( 208 | writeJson(opts.outputTopPath, result.gypiTop, 'gypi', header) 209 | ); 210 | } 211 | 212 | return(Promise.all(writeTasks)); 213 | }); 214 | 215 | return(generateDone); 216 | } 217 | 218 | /** Return an object with contents for an initial binding.gyp file. */ 219 | 220 | export function initGyp(opts: BindingConfig) { 221 | const basePath = opts.basePath; 222 | 223 | const gyp: any = { 224 | targets: [ 225 | { 226 | includes: [ 227 | path.relative(basePath, opts.outputPath) 228 | ], 229 | sources: opts.sourceList.map((src: string) => path.relative(basePath, src)) 230 | } 231 | ] 232 | }; 233 | 234 | if(opts.outputTopPath) { 235 | gyp.includes = [ 236 | path.relative(basePath, opts.outputTopPath) 237 | ]; 238 | } 239 | 240 | return(gyp); 241 | } 242 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | // This file is part of autogypi, copyright (C) 2015-2016 BusFaster Ltd. 2 | // Released under the MIT license, see LICENSE. 3 | 4 | import * as path from 'path'; 5 | import * as cmd from 'commander'; 6 | 7 | import {initGyp, generate, writeJson, AutogypiConfig, GenerateOptions} from './autogypi'; 8 | 9 | type _ICommand = typeof cmd; 10 | interface Command extends _ICommand { 11 | arguments(spec: string): Command; 12 | } 13 | 14 | function parseBool(flag: string) { 15 | const falseTbl: { [key: string]: boolean } = { 16 | '0': true, 17 | 'no': true, 18 | 'false': true 19 | }; 20 | 21 | return(!flag || !falseTbl[flag.toLowerCase()]); 22 | } 23 | 24 | function push(item: string, list: string[]) { 25 | list.push(item); 26 | return(list); 27 | } 28 | 29 | /* tslint:disable:max-line-length */ 30 | 31 | ((cmd.version(require('../package.json').version) as Command) 32 | .description('Generate node-gyp dependency files.') 33 | .option('-r, --root ', 'root path for config files, default is shell working directory') 34 | .option('-c, --config ', 'config file, default autogypi.json') 35 | .option('-o, --output ', 'per-target gypi file to create, default auto.gypi') 36 | .option('-t, --output-top ', 'top-level gypi file to create, default auto-top.gypi') 37 | .option('-T, --no-output-top', 'omit top-level gypi file') 38 | .option('-p, --package ', 'add dependency on another npm package', push, []) 39 | .option('-I, --include-dir ', 'add include directory for header files', push, []) 40 | .option('--save [flag]', 'save changes to config file', parseBool) 41 | .option('--init-gyp [path]', 'create gyp file (default binding.gyp, implies --save) with options:', parseBool) 42 | .option('-s, --source ', ' - add C or C++ source file', push, []) 43 | .action(handleGenerate) 44 | .parse(process.argv) 45 | ); 46 | 47 | /* tslint:enable:max-line-length */ 48 | 49 | handleGenerate(cmd.opts()); 50 | 51 | /** Return sorted unique values from multiple arrays. */ 52 | 53 | function concatUnique(...args: string[][]) { 54 | const tbl: { [key: string]: any } = {}; 55 | 56 | for(let list of args) { 57 | for(let item of list || []) { 58 | tbl[item] = true; 59 | } 60 | } 61 | 62 | return(Object.keys(tbl).sort()); 63 | } 64 | 65 | function handleGenerate(opts: { [key: string]: any }) { 66 | const cwd = process.cwd(); 67 | let root = opts['root'] || cwd; 68 | 69 | function resolve(pathName: string, pathDefault: string) { 70 | if(typeof(pathName) == 'string') { 71 | return(path.resolve(cwd, pathName)); 72 | } else if(pathDefault) { 73 | return(path.resolve(root, pathDefault)); 74 | } else { 75 | return(null); 76 | } 77 | } 78 | 79 | const configPath = resolve(opts['config'], 'autogypi.json'); 80 | let gypPath: string; 81 | 82 | if(opts['initGyp']) gypPath = resolve(opts['initGyp'], 'binding.gyp'); 83 | 84 | if(!opts['root']) { 85 | const refPath = configPath || gypPath; 86 | if(refPath) root = path.dirname(refPath); 87 | } 88 | 89 | let outputPath = resolve(opts['output'], 'auto.gypi'); 90 | let outputTopPath = resolve(opts['outputTop'], 'auto-top.gypi'); 91 | let config: AutogypiConfig; 92 | 93 | try { 94 | config = require(configPath); 95 | } catch(err) { 96 | config = {}; 97 | } 98 | 99 | if(opts['output']) { 100 | config.output = path.relative(path.dirname(configPath), outputPath); 101 | } else { 102 | outputPath = path.resolve(path.dirname(configPath), config['output'] || outputPath); 103 | } 104 | 105 | if(typeof(opts['outputTop']) == 'string') { 106 | config.outputTop = path.relative(path.dirname(configPath), outputTopPath); 107 | } else { 108 | outputTopPath = path.resolve(path.dirname(configPath), config['outputTop'] || outputTopPath); 109 | } 110 | 111 | config['dependencies'] = concatUnique(config.dependencies, opts['package']); 112 | config['includes'] = concatUnique(config.includes, opts['includeDir']); 113 | 114 | if(opts['save'] || opts['initGyp']) writeJson(configPath, config, 'config'); 115 | 116 | if(opts['outputTop'] === false) outputTopPath = null; 117 | 118 | if(opts['initGyp']) { 119 | gypPath = resolve(opts['initGyp'], 'binding.gyp'); 120 | 121 | const gyp = initGyp({ 122 | basePath: path.dirname(gypPath), 123 | outputPath: outputPath, 124 | outputTopPath: outputTopPath, 125 | sourceList: opts['source'].map((src: string) => path.resolve(cwd, src)) 126 | }); 127 | 128 | writeJson(gypPath, gyp, 'gyp template'); 129 | } 130 | 131 | const generateOptions: GenerateOptions = { 132 | configPath: configPath, 133 | outputPath: outputPath, 134 | outputTopPath: outputTopPath 135 | }; 136 | 137 | generate( 138 | generateOptions, 139 | config 140 | ).catch((err: any) => { 141 | console.error('Error: could not generate gypi files:'); 142 | console.error(err); 143 | }); 144 | } 145 | -------------------------------------------------------------------------------- /src/resolve.d.ts: -------------------------------------------------------------------------------- 1 | // This file is part of autogypi, copyright (C) 2015-2016 BusFaster Ltd. 2 | // Released under the MIT license, see LICENSE. 3 | 4 | declare module 'resolve' { 5 | interface ResolveOptions { 6 | basedir?: string; 7 | package?: any; 8 | extensions?: string[]; 9 | readFile?: (path: string, cb: (err: any, data: string) => void) => void; 10 | isFile?: (path: string, cb: (err: any, result: boolean) => void) => void; 11 | packageFilter?: (json: any) => any; 12 | pathFilter?: (json: any, path: string, relativePath: string) => string; 13 | } 14 | 15 | var resolve: (name: string, opts: ResolveOptions, cb: (err: any, path: string) => void) => string; 16 | 17 | export = resolve; 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "noImplicitAny": true, 7 | "outDir": "dist", 8 | "removeComments": false, 9 | "target": "es5" 10 | }, 11 | "files": [ 12 | "typings/main.d.ts", 13 | "src/resolve.d.ts", 14 | 15 | "src/cli.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": true, 4 | "ban": false, 5 | "class-name": true, 6 | "comment-format": [ true, "check-space" ], 7 | "curly": false, 8 | "eofline": true, 9 | "forin": true, 10 | "indent": [ true, "tabs" ], 11 | "interface-name": [ true, "never-prefix" ], 12 | "jsdoc-format": false, 13 | "label-position": true, 14 | "label-undefined": true, 15 | "max-line-length": [ true, 96 ], 16 | "member-access": false, 17 | "member-ordering": [ true, { "order": [ 18 | "constructor", 19 | 20 | "public-static-method", 21 | "private-static-method", 22 | 23 | "public-instance-method", 24 | "private-instance-method", 25 | 26 | "public-instance-field", 27 | "private-instance-field", 28 | 29 | "public-static-field", 30 | "private-static-field" 31 | ] } ], 32 | "new-parens": true, 33 | "no-angle-bracket-type-assertion": true, 34 | "no-any": false, 35 | "no-arg": true, 36 | "no-bitwise": false, 37 | "no-conditional-assignment": true, 38 | "no-consecutive-blank-lines": true, 39 | "no-console": [ true, "log", "warn" ], 40 | "no-construct": true, 41 | "no-constructor-vars": true, 42 | "no-debugger": true, 43 | "no-default-export": true, 44 | "no-duplicate-key": true, 45 | "no-duplicate-variable": true, 46 | "no-empty": true, 47 | "no-eval": true, 48 | "no-inferrable-types": true, 49 | "no-internal-module": true, 50 | "no-invalid-this": true, 51 | "no-namespace": false, 52 | "no-null-keyword": false, 53 | "no-reference": true, 54 | "no-require-imports": false, 55 | "no-shadowed-variable": true, 56 | "no-string-literal": false, 57 | "no-switch-case-fall-through": true, 58 | "no-trailing-whitespace": true, 59 | "no-unreachable": true, 60 | "no-unused-expression": true, 61 | "no-unused-variable": true, 62 | "no-use-before-declare": true, 63 | "no-var-keyword": true, 64 | "no-var-requires": true, 65 | "object-literal-sort-keys": true, 66 | "one-line": [ true, "check-catch", "check-else", "check-finally", "check-open-brace" ], 67 | "one-variable-per-declaration": true, 68 | "quotemark": [ true, "single" ], 69 | "radix": "true", 70 | "semicolon": [ true, "always" ], 71 | "switch-default": true, 72 | "trailing-comma": [ true, { 73 | "multiline": "never", 74 | "singleline": "never" 75 | }], 76 | "triple-equals": false, 77 | "typedef": [ true, "parameter", "arrow-parameter", "property-declaration" ], 78 | "typedef-whitespace": [ true, 79 | { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" }, 80 | { "call-signature": "onespace", "index-signature": "onespace", "parameter": "onespace", "property-declaration": "onespace", "variable-declaration": "onespace" } 81 | ], 82 | "use-isnan": true, 83 | "use-strict": false, 84 | "variable-name": [ true, "check-format", "allow-leading-underscore", "allow-pascal-case" ], 85 | "whitespace": [ true, "check-decl", "check-operator", "check-module", "check-separator", "check-type", "check-typecast" ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientDependencies": { 3 | "commander": "registry:dt/commander#2.3.0+20160317120654", 4 | "node": "registry:dt/node#4.0.0+20160509154515" 5 | }, 6 | "dependencies": { 7 | "bluebird": "registry:npm/bluebird#3.3.4+20160515010139" 8 | } 9 | } 10 | --------------------------------------------------------------------------------