CartoDB-SQL-API/lib/models/formats/ogr/shp.js
Raúl Marín 25f15dfc61 Fix an ogr2ogr export issue when the temporal name is too big
If the final name is going to be too big, use the hash over the proposed
path to create an unique name that fits the requirements of path length
under Linux
2020-05-11 18:35:35 +02:00

134 lines
4.2 KiB
JavaScript

'use strict';
var step = require('step');
var fs = require('fs');
var spawn = require('child_process').spawn;
var Ogr = require('./../ogr');
function ShpFormat () {
}
ShpFormat.prototype = new Ogr('shp');
ShpFormat.prototype._contentType = 'application/zip; charset=utf-8';
ShpFormat.prototype._fileExtension = 'zip';
// As of GDAL 1.10 SRID detection is bogus, so we use
// our own method. See:
// http://trac.osgeo.org/gdal/ticket/5131
// http://trac.osgeo.org/gdal/ticket/5287
// http://github.com/CartoDB/CartoDB-SQL-API/issues/110
// http://github.com/CartoDB/CartoDB-SQL-API/issues/116
ShpFormat.prototype._needSRS = true;
ShpFormat.prototype.generate = function (options, callback) {
this.toSHP(options, callback);
};
ShpFormat.prototype.toSHP = function (options, callback) {
var dbname = options.database;
var userId = options.user_id;
var gcol = options.gn;
var sql = options.sql;
var skipfields = options.skipfields;
var filename = options.filename;
var fmtObj = this;
var zip = global.settings.zipCommand || 'zip';
var zipOptions = '-qrj';
var tmpdir = global.settings.tmpDir || '/tmp';
var reqKey = this.limitPathname(['shp', dbname, userId, gcol, this.generateMD5(sql)].concat(skipfields).join(':'));
var outdirpath = tmpdir + '/sqlapi-' + process.pid + '-' + reqKey;
var zipfile = outdirpath + '.zip';
var shapefile = outdirpath + '/' + filename + '.shp';
// TODO: following tests:
// - fetch query with no "the_geom" column
step(
function createOutDir () {
fs.mkdir(outdirpath, 0o777, this);
},
function spawnDumper (err) {
if (err) {
throw err;
}
fmtObj.toOGR(options, 'ESRI Shapefile', shapefile, this);
},
function doZip (err) {
if (err) {
throw err;
}
var next = this;
var child = spawn(zip, [zipOptions, zipfile, outdirpath]);
child.on('error', function (err) {
next(new Error('Error executing zip command, ' + err));
});
var stderrData = [];
child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
stderrData.push(data);
});
child.on('exit', function (code) {
if (code !== 0) {
var errMessage = 'Zip command return code ' + code;
if (stderrData.length) {
errMessage += ', Error: ' + stderrData.join('\n');
}
return next(new Error(errMessage));
}
return next();
});
},
function cleanupDir (topError) {
var next = this;
// Unlink the dir content
var unlinkall = function (dir, files, finish) {
var f = files.shift();
if (!f) { finish(null); return; }
var fn = dir + '/' + f;
fs.unlink(fn, function (err) {
if (err) {
console.log('Unlinking ' + fn + ': ' + err);
finish(err);
} else {
unlinkall(dir, files, finish);
}
});
};
fs.readdir(outdirpath, function (err, files) {
if (err) {
if (err.code !== 'ENOENT') {
next(new Error([topError, err].join('\n')));
} else {
next(topError);
}
} else {
unlinkall(outdirpath, files, function (/* err */) {
fs.rmdir(outdirpath, function (err) {
if (err) {
console.log('Removing dir ' + outdirpath + ': ' + err);
}
next(topError, zipfile);
});
});
}
});
},
function finalStep (err, zipfile) {
callback(err, zipfile);
}
);
};
module.exports = ShpFormat;