async function fetch_packages() {
const resp = await fetch('../packages.csv');
const data = await resp.text();
return data
.split('\n')
.map(line => line.split(';'))
.filter(fields => fields.length >= 5)
.map(fields => ({
section: fields[0],
id: fields[1],
desc: fields[2],
// fields[3] is the licence
flags: fields[4].split(' '),
}));
}
async function fetch_commit_info() {
const resp = await fetch('../commit.csv');
const data = await resp.text();
const fields = data.split(';');
return {
sha: fields[0] || '',
when: fields[1] || '',
branch: fields[2] || '',
};
}
function create_device_bars(packages) {
const devices = [{
name: 'Raspberry Pi 0/1',
flags: ['videocore', 'arm', 'armv6'],
hover: 'VideoCore + ARMv6',
}, {
name: 'Raspberry Pi 2',
flags: ['videocore', 'arm', 'armv7'],
hover: 'VideoCore + ARMv7',
},{
name: 'Raspberry Pi 3',
flags: ['videocore', 'arm', 'armv8'],
hover: 'VideoCore + ARMv8',
}, {
name: 'Raspberry Pi 4',
flags: ['kms', 'arm', 'armv8'],
hover: 'DRM/KMS + ARMv8',
}, {
name: 'Odroid C1/XU3/XU4',
flags: ['mali', 'arm', 'armv7'],
hover: 'Mali + ARMv7',
}, {
name: 'Odroid C2',
flags: ['mali', 'aarch64'],
hover: 'Mali + AArch64',
}, {
name: 'Desktop Linux',
flags: ['x11', 'x86'],
hover: 'X11 + x86',
},
];
const ui_holder = document.createElement('ul');
devices
.map(device => {
const label = document.createElement('span');
label.innerText = device.name;
const bar = document.createElement('progress');
bar.max = packages.length;
bar.value = packages
.filter(pkg => device.flags.every(flag => !pkg.flags.includes('!' + flag)))
.length;
bar.title = `${device.hover}\n${bar.value} / ${bar.max}`;
const percent = document.createElement('span');
percent.innerText = Math.round(100 * bar.value / bar.max) + '%';
const row = document.createElement('li');
row.appendChild(label);
row.appendChild(bar);
row.appendChild(percent);
return row;
})
.forEach(row => ui_holder.appendChild(row));
document.getElementById('devices').appendChild(ui_holder);
}
function create_commit_info(commit) {
const date = commit.when.slice(0, 10);
const time = commit.when.slice(11, 16);
const text = `Last update: ${date} ${time}, ${commit.branch}
branch at ${commit.sha}
`;
document.getElementById('commit').innerHTML = text;
}
function package_enabled_for(pkg, flag) {
const video_flag_synonyms = {
'videocore' : [ 'arm', 'rpi', 'rpi1', 'rpi2', 'rpi3', 'dispmanx', 'gles' ],
'mali' : [ 'arm' , 'gles' ],
'kms' : [ 'arm' , 'rpi', 'rpi4', 'dispmanx', 'mesa' , 'gles3' ],
'x11' : [ 'x86' , '64bit', 'mesa' ]
};
var equivs = (video_flag_synonyms[flag] ? [flag].concat(video_flag_synonyms[flag]) : [flag]);
if ( pkg.flags.includes('!all') ) {
return _flags_include(pkg.flags, equivs) && !_flags_exclude(pkg.flags, equivs);
} else {
return !_flags_exclude(pkg.flags, equivs);
}
}
function _flags_include(pkg_flags, flags) {
return flags.reduce( (acc, flag) => acc || pkg_flags.includes(flag), false);
}
function _flags_exclude(pkg_flags, flags) {
return flags.reduce( (acc, flag) => acc || pkg_flags.includes('!' + flag), false);
}
function append_pkg_text_cell(parent, klass, text) {
const cell = document.createElement('td');
cell.innerText = text;
if (Array.isArray(klass))
klass.forEach(k => cell.classList.add(k));
else
cell.classList.add(klass);
parent.appendChild(cell);
}
function append_pkg_flag_cell(parent, klass, is_pass) {
const cell = document.createElement('td');
cell.innerText = is_pass ? '\u2713' : '\u2717';
cell.classList.add('flag', klass, is_pass ? 'pass' : 'fail');
parent.appendChild(cell);
}
function create_section_thead() {
const thead = document.createElement('thead');
append_pkg_text_cell(thead, 'id', 'Package');
append_pkg_text_cell(thead, 'desc', 'Description');
append_pkg_text_cell(thead, ['flag', 'video'], 'VideoCore');
append_pkg_text_cell(thead, ['flag', 'video'], 'Mali');
append_pkg_text_cell(thead, ['flag', 'video'], 'DRM/KMS');
append_pkg_text_cell(thead, ['flag', 'video'], 'X11');
append_pkg_text_cell(thead, ['flag', 'cpu'], 'ARMv6');
append_pkg_text_cell(thead, ['flag', 'cpu'], 'ARMv7');
append_pkg_text_cell(thead, ['flag', 'cpu'], 'ARMv8 (32 bit)');
append_pkg_text_cell(thead, ['flag', 'cpu'], 'AArch64');
append_pkg_text_cell(thead, ['flag', 'cpu'], 'x86');
thead.querySelector('.flag.video').classList.add('first');
thead.querySelector('.flag.cpu').classList.add('first');
return thead;
}
function create_section_row(pkg) {
const row = document.createElement('tr');
row.title='Script flags: ' + pkg.flags.join(' ');
append_pkg_text_cell(row, 'id', pkg.id);
append_pkg_text_cell(row, 'desc', pkg.desc);
append_pkg_flag_cell(row, 'video', package_enabled_for(pkg, 'videocore'));
append_pkg_flag_cell(row, 'video', package_enabled_for(pkg, 'mali'));
append_pkg_flag_cell(row, 'video', package_enabled_for(pkg, 'kms'));
append_pkg_flag_cell(row, 'video', package_enabled_for(pkg, 'x11'));
append_pkg_flag_cell(row, 'cpu', !pkg.flags.includes('!arm') && !pkg.flags.includes('!armv6'));
append_pkg_flag_cell(row, 'cpu', !pkg.flags.includes('!arm') && !pkg.flags.includes('!armv7'));
append_pkg_flag_cell(row, 'cpu', !pkg.flags.includes('!arm') && !pkg.flags.includes('!armv8'));
append_pkg_flag_cell(row, 'cpu', !pkg.flags.includes('!aarch64'));
append_pkg_flag_cell(row, 'cpu', !pkg.flags.includes('!x86'));
row.querySelector('.flag.video').classList.add('first');
row.querySelector('.flag.cpu').classList.add('first');
return row;
}
function create_package_sections(packages) {
const section_ids = [
'core',
'main',
'opt',
'exp',
'driver',
'config',
'',
];
const section_names = {
opt: 'optional',
exp: 'experimental',
config: 'configuration',
'': 'other',
};
const sections = [];
section_ids.forEach(id => sections[id] = []);
packages.forEach(pkg => {
const section = sections[pkg.section] || sections[''];
section.push(pkg);
});
const fragment = new DocumentFragment();
section_ids
.filter(id => sections[id])
.forEach(id => {
const ui_container = document.createElement('section');
const ui_title = document.createElement('h2');
ui_title.innerText = section_names[id] || id;
ui_container.appendChild(ui_title);
const ui_table = document.createElement('table');
ui_table.appendChild(create_section_thead());
sections[id]
.sort((a, b) => a.id.localeCompare(b.id))
.map(pkg => create_section_row(pkg))
.forEach(row => ui_table.appendChild(row));
ui_container.appendChild(ui_table);
fragment.appendChild(ui_container);
});
document.getElementById('packages').appendChild(fragment);
document.querySelector('table .flag.video').classList.add('first');
document.querySelector('table .flag.cpu').classList.add('first');
}
window.onload = async () => {
const packages = await fetch_packages();
const commit = await fetch_commit_info();
create_device_bars(packages);
create_commit_info(commit);
create_package_sections(packages);
};