зеркало из https://github.com/docker/kitematic.git
Improved pull image loading
This commit is contained in:
Родитель
037bc18a6d
Коммит
4f80c5d0db
|
@ -2,6 +2,7 @@ var _ = require('underscore');
|
||||||
var $ = require('jquery');
|
var $ = require('jquery');
|
||||||
var React = require('react/addons');
|
var React = require('react/addons');
|
||||||
var Radial = require('./Radial.react');
|
var Radial = require('./Radial.react');
|
||||||
|
var ContainerProgress = require('./ContainerProgress.react');
|
||||||
var ContainerHomePreview = require('./ContainerHomePreview.react');
|
var ContainerHomePreview = require('./ContainerHomePreview.react');
|
||||||
var ContainerHomeLogs = require('./ContainerHomeLogs.react');
|
var ContainerHomeLogs = require('./ContainerHomeLogs.react');
|
||||||
var ContainerHomeFolders = require('./ContainerHomeFolders.react');
|
var ContainerHomeFolders = require('./ContainerHomeFolders.react');
|
||||||
|
@ -51,22 +52,29 @@ var ContainerHome = React.createClass({
|
||||||
);
|
);
|
||||||
} else if (this.props.container && this.props.container.State.Downloading) {
|
} else if (this.props.container && this.props.container.State.Downloading) {
|
||||||
if (this.props.container.Progress !== undefined) {
|
if (this.props.container.Progress !== undefined) {
|
||||||
if (this.props.container.Progress > 0) {
|
|
||||||
body = (
|
let fields = [];
|
||||||
<div className="details-progress">
|
let values = [];
|
||||||
<h2>Downloading Image</h2>
|
let sum = 0.0;
|
||||||
<Radial progress={Math.min(Math.round(this.props.container.Progress), 99)} thick={true} gray={true}/>
|
|
||||||
</div>
|
for (let i = 0; i < this.props.container.Progress.amount; i++) {
|
||||||
);
|
|
||||||
} else {
|
values.push(Math.round(this.props.container.Progress.progress[i].value));
|
||||||
body = (
|
sum += this.props.container.Progress.progress[i].value;
|
||||||
<div className="details-progress">
|
|
||||||
<h2>Downloading Image</h2>
|
|
||||||
<Radial spin="true" progress="90" thick={true} transparent={true}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sum = sum / this.props.container.Progress.amount;
|
||||||
|
|
||||||
|
fields.push(<h2>{Math.round(sum*100)/100}%</h2>)
|
||||||
|
fields.push(<ContainerProgress pBar1={values[0]} pBar2={values[1]} pBar3={values[2]} pBar4={values[3]} />);
|
||||||
|
|
||||||
|
body = (
|
||||||
|
<div className="details-progress">
|
||||||
|
<h2>Downloading Image</h2>
|
||||||
|
{fields}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
} else if (this.props.container.State.Waiting) {
|
} else if (this.props.container.State.Waiting) {
|
||||||
body = (
|
body = (
|
||||||
<div className="details-progress">
|
<div className="details-progress">
|
||||||
|
|
|
@ -97,11 +97,15 @@ class ContainerStore {
|
||||||
this.setState({containers});
|
this.setState({containers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Receives the name of the container and columns of progression
|
||||||
|
// A column represents progression for one or more layers
|
||||||
progress ({name, progress}) {
|
progress ({name, progress}) {
|
||||||
let containers = this.containers;
|
let containers = this.containers;
|
||||||
|
|
||||||
if (containers[name]) {
|
if (containers[name]) {
|
||||||
containers[name].Progress = progress;
|
containers[name].Progress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({containers});
|
this.setState({containers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,9 +178,16 @@ export default {
|
||||||
delete this.placeholders[name];
|
delete this.placeholders[name];
|
||||||
localStorage.setItem('placeholders', JSON.stringify(this.placeholders));
|
localStorage.setItem('placeholders', JSON.stringify(this.placeholders));
|
||||||
this.createContainer(name, {Image: imageName});
|
this.createContainer(name, {Image: imageName});
|
||||||
}, progress => {
|
},
|
||||||
|
|
||||||
|
// progress is actually the progression PER LAYER (combined in columns)
|
||||||
|
// not total because it's not accurate enough
|
||||||
|
progress => {
|
||||||
containerServerActions.progress({name, progress});
|
containerServerActions.progress({name, progress});
|
||||||
}, () => {
|
},
|
||||||
|
|
||||||
|
|
||||||
|
() => {
|
||||||
containerServerActions.waiting({name, waiting: true});
|
containerServerActions.waiting({name, waiting: true});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -310,7 +317,7 @@ export default {
|
||||||
stream.setEncoding('utf8');
|
stream.setEncoding('utf8');
|
||||||
stream.on('data', json => {
|
stream.on('data', json => {
|
||||||
let data = JSON.parse(json);
|
let data = JSON.parse(json);
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
|
|
||||||
if (data.status === 'pull' || data.status === 'untag' || data.status === 'delete') {
|
if (data.status === 'pull' || data.status === 'untag' || data.status === 'delete') {
|
||||||
return;
|
return;
|
||||||
|
@ -344,6 +351,9 @@ export default {
|
||||||
return !existingIds.has(layerSize.Id);
|
return !existingIds.has(layerSize.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("existingIds:" + existingIds.size)
|
||||||
|
console.log("layersToDownload:" + layersToDownload.length)
|
||||||
|
|
||||||
this.client.pull(repository + ':' + tag, (err, stream) => {
|
this.client.pull(repository + ':' + tag, (err, stream) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
|
@ -351,16 +361,45 @@ export default {
|
||||||
}
|
}
|
||||||
stream.setEncoding('utf8');
|
stream.setEncoding('utf8');
|
||||||
|
|
||||||
|
// layerProgress contains progression infos for all layers
|
||||||
let layerProgress = layersToDownload.reduce(function (r, layer) {
|
let layerProgress = layersToDownload.reduce(function (r, layer) {
|
||||||
if (_.findWhere(images, {Id: layer.Id})) {
|
if (_.findWhere(images, {Id: layer.Id})) {
|
||||||
r[layer.Id] = 1;
|
// If the layer is already here, we set current and total to 1
|
||||||
|
r[layer.Id] = {current:1, total:1, column:-1};
|
||||||
} else {
|
} else {
|
||||||
r[layer.Id] = 0;
|
// At this point, the total layer size is unknown
|
||||||
|
// so we set total to -1 to avoid displaying it
|
||||||
|
r[layer.Id] = {current:0, total:-1, column:-1};
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
let timeout = null;
|
|
||||||
|
|
||||||
|
let layersToLoad = _.keys(layerProgress).length;
|
||||||
|
|
||||||
|
console.log("nbLayers:" + layersToLoad)
|
||||||
|
|
||||||
|
// Split the loading in a few columns for more feedback
|
||||||
|
let columns = {};
|
||||||
|
columns.amount = 4; // arbitrary
|
||||||
|
columns.progress = []; // layerIDs, nbLayers, maxLayers, progress value
|
||||||
|
columns.toFill = 0; // the current column index, waiting for layer IDs to be displayed
|
||||||
|
|
||||||
|
for (let i = 0; i < columns.amount; i++)
|
||||||
|
{
|
||||||
|
let layerAmount = Math.ceil(layersToLoad / (columns.amount - i))
|
||||||
|
layersToLoad -= layerAmount;
|
||||||
|
columns.progress[i] = { layerIDs:[], nbLayers:0 , maxLayers:layerAmount , value:0.0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// scheduled to inform about progression at given interval
|
||||||
|
let tick = null;
|
||||||
|
|
||||||
|
|
||||||
|
// data is associated with one layer only (can be identified with id)
|
||||||
stream.on('data', str => {
|
stream.on('data', str => {
|
||||||
var data = JSON.parse(str);
|
var data = JSON.parse(str);
|
||||||
|
|
||||||
|
@ -374,34 +413,79 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.status === 'Already exists') {
|
if (data.status === 'Already exists') {
|
||||||
layerProgress[data.id] = 1;
|
|
||||||
|
//layerProgress[data.id].current = 1;
|
||||||
|
//layerProgress[data.id].total = 1;
|
||||||
|
|
||||||
} else if (data.status === 'Downloading') {
|
} else if (data.status === 'Downloading') {
|
||||||
let current = data.progressDetail.current;
|
|
||||||
let total = data.progressDetail.total;
|
|
||||||
|
|
||||||
if (total <= 0) {
|
// aduermael: How total could be <= 0 ?
|
||||||
progressCallback(0);
|
|
||||||
return;
|
// if (data.progressDetail.total <= 0) {
|
||||||
} else {
|
// progressCallback(0);
|
||||||
layerProgress[data.id] = current / total;
|
// return;
|
||||||
|
// } else {
|
||||||
|
|
||||||
|
layerProgress[data.id].current = data.progressDetail.current;
|
||||||
|
layerProgress[data.id].total = data.progressDetail.total;
|
||||||
|
|
||||||
|
// Assign to a column if not done yet
|
||||||
|
if (layerProgress[data.id].column == -1)
|
||||||
|
{
|
||||||
|
// test if we can still add layers to that column
|
||||||
|
if (columns.progress[columns.toFill].nbLayers == columns.progress[columns.toFill].maxLayers) columns.toFill++;
|
||||||
|
|
||||||
|
layerProgress[data.id].column = columns.toFill;
|
||||||
|
columns.progress[columns.toFill].layerIDs.push(data.id);
|
||||||
|
columns.progress[columns.toFill].nbLayers++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sum = _.values(layerProgress).reduce((pv, sv) => pv + sv, 0);
|
//}
|
||||||
let numlayers = _.keys(layerProgress).length;
|
|
||||||
|
|
||||||
var totalProgress = sum / numlayers * 100;
|
if (!tick) {
|
||||||
|
tick = setInterval( function(){
|
||||||
|
// console.log(JSON.stringify(layerProgress))
|
||||||
|
|
||||||
if (!timeout) {
|
// update values
|
||||||
progressCallback(totalProgress);
|
for (let i = 0; i < columns.amount; i++)
|
||||||
timeout = setTimeout(() => {
|
{
|
||||||
timeout = null;
|
columns.progress[i].value = 0.0;
|
||||||
}, 100);
|
|
||||||
|
// Start only if the column has accurate values for all layers
|
||||||
|
if (columns.progress[i].nbLayers == columns.progress[i].maxLayers)
|
||||||
|
{
|
||||||
|
let layer;
|
||||||
|
let totalSum = 0;
|
||||||
|
let currentSum = 0;
|
||||||
|
|
||||||
|
for (let j = 0; j < columns.progress[i].nbLayers; j++)
|
||||||
|
{
|
||||||
|
layer = layerProgress[columns.progress[i].layerIDs[j]];
|
||||||
|
totalSum += layer.total;
|
||||||
|
currentSum += layer.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalSum > 0) columns.progress[i].value = 100.0 * currentSum / totalSum;
|
||||||
|
else columns.progress[i].value = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progressCallback(columns);
|
||||||
|
|
||||||
|
},33);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('end', function () {
|
stream.on('end', function () {
|
||||||
|
|
||||||
|
clearInterval(tick);
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Загрузка…
Ссылка в новой задаче