This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/services/datafile-service.js
Joseph Schorr ba0ecf03dd Fix bugs around reading in datafiles and Dockerfiles
We now properly try to read archives in all three formats. If none are valid, the dataFileService.readDataArrayAsPossibleArchive fails (as it should), and then the Dockerfile service will try to read the file directly as a Dockerfile.

Fixes #1889
Fixes #1891
2016-09-29 11:36:57 +02:00

176 lines
4.6 KiB
JavaScript

/**
* Service which provides helper methods for downloading a data file from a URL, and extracting
* its contents as .tar, .tar.gz, or .zip file. Note that this service depends on external
* library code in the lib/ directory:
* - jszip.min.js
* - Blob.js
* - zlib.js
*/
angular.module('quay').factory('DataFileService', [function() {
var dataFileService = {};
dataFileService.getName_ = function(filePath) {
var parts = filePath.split('/');
return parts[parts.length - 1];
};
dataFileService.tryAsZip_ = function(buf, success, failure) {
var zip = null;
var zipFiles = null;
try {
var zip = new JSZip(buf);
zipFiles = zip.files;
} catch (e) {
failure();
return;
}
var files = [];
for (var filePath in zipFiles) {
if (zipFiles.hasOwnProperty(filePath)) {
files.push({
'name': dataFileService.getName_(filePath),
'path': filePath,
'canRead': true,
'toBlob': (function(fp) {
return function() {
return new Blob([zip.file(fp).asArrayBuffer()]);
};
}(filePath))
});
}
}
success(files);
};
dataFileService.tryAsTarGz_ = function(buf, success, failure) {
var gunzip = new Zlib.Gunzip(new Uint8Array(buf));
var plain = null;
try {
plain = gunzip.decompress();
} catch (e) {
failure();
return;
}
if (plain.byteLength == 0) {
plain = buf;
}
dataFileService.tryAsTar_(plain, success, failure);
};
dataFileService.tryAsTar_ = function(buf, success, failure) {
var collapsePath = function(originalPath) {
// Tar files can contain entries of the form './', so we need to collapse
// those paths down.
var parts = originalPath.split('/');
for (var i = parts.length - 1; i >= 0; i--) {
var part = parts[i];
if (part == '.') {
parts.splice(i, 1);
}
}
return parts.join('/');
};
var handler = new Untar(new Uint8Array(buf));
handler.process(function(status, read, files, err) {
switch (status) {
case 'error':
failure(err);
break;
case 'done':
var processed = [];
for (var i = 0; i < files.length; ++i) {
var currentFile = files[i];
var path = collapsePath(currentFile.meta.filename);
if (path == '' || path == 'pax_global_header') { continue; }
processed.push({
'name': dataFileService.getName_(path),
'path': path,
'canRead': true,
'toBlob': (function(currentFile) {
return function() {
return new Blob([currentFile.buffer], {type: 'application/octet-binary'});
};
}(currentFile))
});
}
success(processed);
break;
}
});
};
dataFileService.blobToString = function(blob, callback) {
var reader = new FileReader();
reader.onload = function(event){
callback(reader.result);
};
reader.readAsText(blob);
};
dataFileService.arrayToString = function(buf, callback) {
var bb = new Blob([buf], {type: 'application/octet-binary'});
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
};
f.onerror = function(e) {
callback(null);
};
f.onabort = function(e) {
callback(null);
};
f.readAsText(bb);
};
dataFileService.readDataArrayAsPossibleArchive = function(buf, success, failure) {
dataFileService.tryAsZip_(buf, success, function() {
dataFileService.tryAsTarGz_(buf, success, function() {
dataFileService.tryAsTar_(buf, success, failure);
});
});
};
dataFileService.downloadDataFileAsArrayBuffer = function($scope, url, progress, error, loaded) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onprogress = function(e) {
$scope.$apply(function() {
var percentLoaded;
if (e.lengthComputable) {
progress(e.loaded / e.total);
}
});
};
request.onerror = function() {
$scope.$apply(function() {
error();
});
};
request.onload = function() {
if (this.status == 200) {
$scope.$apply(function() {
var uint8array = new Uint8Array(request.response);
loaded(uint8array);
});
return;
}
};
request.send();
};
return dataFileService;
}]);