├── .npmignore ├── CHANGELOG.md ├── README.md ├── bin └── tl.js ├── lib ├── commands │ ├── copy.js │ └── info.js └── modules.js └── package.json /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !lib/** 4 | !bin/** 5 | !index.js 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | ## v0.10.2 - 7/10/18 4 | 5 | * Use GitHub archive URL instead of git repository for `nomnom` dep 6 | 7 | ## v0.10.1 - 6/14/17 8 | 9 | * Fix dependency `require`s 10 | 11 | ## v0.10.0 - 6/13/17 12 | 13 | * Update dependencies 14 | 15 | ## v0.9.0 - 5/9/16 16 | 17 | * Upgrade `tilelive-modules` 18 | * Add `--quiet` (`-q`) option to `copy` command 19 | 20 | ## v0.8.1 - 3/15/16 21 | 22 | * Pull in MBTiles optimizations from `tilelive-streaming` 23 | 24 | ## v0.8.0 - 3/7/16 25 | 26 | * Drop `render` command, as including `mapnik` as a dependency (indirectly or 27 | otherwise) wasn't worth the problems that it was causing 28 | 29 | ## v0.7.0 2/16/16 30 | 31 | * Increase `UV_THREADPOOL_SIZE` 32 | * Upgrade to `tilelive-cache@^0.6.1` with improvements to `close()` handling 33 | * Display usage when no command was provided 34 | 35 | ## v0.6.0 1/7/16 36 | 37 | * Include changes merged via GitHub 38 | * Pass `scale` parameter to sources 39 | 40 | ## v0.5.0 1/7/16 41 | 42 | * Update dependencies 43 | 44 | ## v0.4.0 6/30/15 45 | 46 | * Update `tilelive-streaming` for compatibility with Node-0.12.x and iojs 47 | * Update `abaculus` for compatibility with Node-0.12.x and iojs 48 | 49 | ## v0.3.4 - 5/9/15 50 | 51 | * Opt into retries if available 52 | * Pick up fixes in `tilelive-streaming` 53 | 54 | ## v0.3.3 - 4/30/15 55 | 56 | * Upstream concurrency improvements in `tilelive-streaming` 57 | 58 | ## v0.3.2 - 4/14/15 59 | 60 | * Improve error logging when loading tilelive modules 61 | * Update `tilelive-streaming` with concurrent buffering (for better throughput 62 | with flakey sources) 63 | 64 | ## v0.3.1 - 1/2/15 65 | 66 | * Update `tilelive-streaming` for proper buffering (effectively increasing 67 | concurrency) 68 | 69 | ## v0.3.0 - 11/18/14 70 | 71 | * Add `render` command 72 | 73 | ## v0.2.1 - 10/14/14 74 | 75 | * Re-published without junk lying around 76 | 77 | ## v0.2.0 - 10/14/14 78 | 79 | * Auto-register tilelive modules via `tilelive-modules` 80 | 81 | ## v0.1.1 - 10/13/14 82 | 83 | * Relax `tilelive` version dependency to play better with other modules 84 | * Depend on fixed `tilelive-streaming` 85 | 86 | ## v0.1.0 - 6/6/14 87 | 88 | * Initial release 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tl 2 | 3 | A command line alternative to 4 | [`tilelive`](https://github.com/mapbox/tilelive.js) that supports streaming 5 | copies and static image rendering. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | npm install tl 11 | npm install mbtiles tilelive-file 12 | # install any other tilelive modules you'd like to read/write from 13 | ``` 14 | 15 | ## Usage 16 | 17 | Copy tiles from a filesystem to an MBTiles archive (assumes that 18 | `tilelive-file` and `mbtiles` are installed): 19 | 20 | ```bash 21 | tl copy file://./tiles mbtiles://./tiles.mbtiles 22 | ``` 23 | 24 | Render a [TM2](https://github.com/mapbox/tm2) style for a small area into an 25 | MBTiles archive: 26 | 27 | ```bash 28 | npm install mbtiles tilelive-tmstyle tilelive-mapbox tilejson \ 29 | tilelive-vector@^0.13.0 30 | tl copy 31 | -z 6 -Z 6 -b "-124.4096 32.5343 -114.1308 42.0095" \ 32 | tmstyle://./project.tm2/ mbtiles://./tiles.mbtiles 33 | ``` 34 | 35 | Copy tiles from an MBTiles archive to S3. 36 | 37 | ```bash 38 | tl copy mbtiles://./tiles.mbtiles "s3://bucket-name/{z}/{x}/{y}.png?acl=public-read" 39 | ``` 40 | 41 | ## Caveats 42 | 43 | Some tilelive providers use other providers but don't depend on them directly 44 | (relying on `tilelive.load()`), so you may need to install (and `--require|-r`) 45 | some modules that you're not using directly. 46 | 47 | For example, [`tilelive-tmstyle`](https://github.com/mojodna/tilelive-tmstyle) 48 | often loads data using 49 | [`tilelive-mapbox`](https://github.com/mojodna/tilelive-mapbox), which actually 50 | uses [`tilejson`](https://github.com/mapbox/node-tilejson) under the hood to do 51 | the fetching. Rendering is then done using 52 | [`tilelive-vector`](https://github.com/mapbox/tilelive-vector) (which is 53 | declared as a peer dependency of `tilelive-tmstyle`, so versions may not always 54 | match up to whatever's most up-to-date). 55 | -------------------------------------------------------------------------------- /bin/tl.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | // increase the libuv threadpool size to 1.5x the number of logical CPUs. 5 | process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || Math.ceil(Math.max(4, require('os').cpus().length * 1.5)); 6 | 7 | var fs = require("fs"), 8 | path = require("path"); 9 | 10 | var parser = require("nomnom"), 11 | tilelive = require("tilelive-cache")(require("tilelive-streaming")(require("@mapbox/tilelive"))); 12 | 13 | parser.options({ 14 | version: { 15 | abbr: "v", 16 | flag: true, 17 | help: "Show version info", 18 | callback: function() { 19 | return "tl v" + require("../package.json").version; 20 | } 21 | } 22 | }); 23 | 24 | var commandDir = path.join(__dirname, "..", "lib", "commands"); 25 | 26 | fs.readdirSync(commandDir) 27 | .filter(function(x) { 28 | return path.extname(x) === ".js"; 29 | }) 30 | .forEach(function(x) { 31 | require(path.join(commandDir, x))(parser, tilelive); 32 | }); 33 | 34 | var args = parser.parse(); 35 | 36 | if (args.command) { 37 | // no command matched 38 | parser.parse("--help"); 39 | process.exit(1); 40 | } 41 | -------------------------------------------------------------------------------- /lib/commands/copy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var fs = require("fs"), 4 | path = require("path"); 5 | 6 | var async = require("async"); 7 | 8 | module.exports = function(parser, tilelive) { 9 | parser.command("copy") 10 | .options({ 11 | source: { 12 | position: 1, 13 | help: "source URI", 14 | required: true 15 | }, 16 | sink: { 17 | position: 2, 18 | help: "sink URI", 19 | required: true 20 | }, 21 | bounds: { 22 | abbr: "b", 23 | metavar: "BBOX", 24 | help: "WGS84 bounding box", 25 | default: [-180, -85.0511, 180, 85.0511], 26 | transform: function(val) { 27 | return val.split(" ").map(Number); 28 | } 29 | }, 30 | minzoom: { 31 | full: "min-zoom", 32 | abbr: "z", 33 | metavar: "ZOOM", 34 | help: "Min zoom (inclusive)", 35 | default: 0 36 | }, 37 | maxzoom: { 38 | full: "max-zoom", 39 | abbr: "Z", 40 | metavar: "ZOOM", 41 | help: "Max zoom (inclusive)", 42 | default: 22 43 | }, 44 | require: { 45 | abbr: "r", 46 | metavar: "MODULE", 47 | help: "Require a specific tilelive module", 48 | list: true 49 | }, 50 | scheme: { 51 | abbr: "s", 52 | metavar: "SCHEME", 53 | help: "Copy scheme", 54 | choices: ["scanline", "pyramid"], 55 | default: "scanline" 56 | }, 57 | info: { 58 | abbr: "i", 59 | metavar: "FILE", 60 | help: "TileJSON" 61 | }, 62 | quiet: { 63 | abbr: "q", 64 | flag: true, 65 | help: "Quiet" 66 | } 67 | }) 68 | .callback(function(opts) { 69 | require("../modules")(tilelive, opts); 70 | 71 | return async.parallel({ 72 | source: async.apply(tilelive.load, opts.source), 73 | sink: async.apply(tilelive.load, opts.sink) 74 | }, function(err, res) { 75 | if (err) { 76 | throw err; 77 | } 78 | 79 | if (opts.info) { 80 | opts.info = JSON.parse(fs.readFileSync(path.resolve(opts.info))); 81 | } 82 | 83 | var source = res.source, 84 | sink = res.sink, 85 | writeStream = sink.createWriteStream({ 86 | info: opts.info 87 | }); 88 | 89 | source 90 | .createReadStream({ 91 | minzoom: opts.minzoom, 92 | maxzoom: opts.maxzoom, 93 | bounds: opts.bounds 94 | }) 95 | .pipe(writeStream) 96 | .on("tile", function(tile) { 97 | if (!opts.quiet) { 98 | console.log("%d/%d/%d\t%d", tile.z, tile.x, tile.y, tile.length); 99 | } 100 | }); 101 | }); 102 | }) 103 | .help("copy data between tilelive providers"); 104 | }; 105 | -------------------------------------------------------------------------------- /lib/commands/info.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function(parser, tilelive) { 4 | parser.command("info") 5 | .options({ 6 | uri: { 7 | position: 1, 8 | help: "tilelive URI" 9 | }, 10 | require: { 11 | abbr: "r", 12 | metavar: "MODULE", 13 | help: "Require a specific tilelive module", 14 | list: true 15 | } 16 | }) 17 | .callback(function(opts) { 18 | require("../modules")(tilelive, opts); 19 | 20 | return tilelive.load(opts.uri, function(err, src) { 21 | if (err) { 22 | throw err; 23 | } 24 | 25 | return src.getInfo(function(err, info) { 26 | if (err) { 27 | throw err; 28 | } 29 | 30 | console.log("%j", info); 31 | }); 32 | }); 33 | }) 34 | .help("get info"); 35 | }; 36 | -------------------------------------------------------------------------------- /lib/modules.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var modules = require("tilelive-modules"); 4 | 5 | module.exports = function(tilelive, options) { 6 | options = options || {}; 7 | options.require = options.require || []; 8 | 9 | modules.concat(options.require).forEach(function(name) { 10 | var mod; 11 | 12 | try { 13 | mod = require(name); 14 | } catch (err) { 15 | if (err.code !== "MODULE_NOT_FOUND") { 16 | console.warn(err.stack); 17 | } 18 | return; 19 | } 20 | 21 | try { 22 | if (typeof(mod.registerProtocols) === "function") { 23 | mod.registerProtocols(tilelive); 24 | } else { 25 | mod(tilelive, { 26 | retry: true 27 | }); 28 | } 29 | } catch (err) { 30 | console.warn(err.stack); 31 | } 32 | }); 33 | 34 | return tilelive; 35 | }; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tl", 3 | "version": "0.10.2", 4 | "description": "A command line tool for manipulating data available via tilelive providers", 5 | "author": "Seth Fitzsimmons ", 6 | "bin": "bin/tl.js", 7 | "license": "ISC", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/mojodna/tl.git" 11 | }, 12 | "dependencies": { 13 | "async": "^1.5.2", 14 | "nomnom": "https://github.com/mojodna/nomnom/tarball/options-with-spaces", 15 | "@mapbox/tilelive": "*", 16 | "tilelive-cache": "^0.7.1", 17 | "tilelive-modules": "^0.3.0", 18 | "tilelive-streaming": "^0.7.0" 19 | } 20 | } 21 | --------------------------------------------------------------------------------