repoindex/web/js/packagemanagement.js

352 lines
19 KiB
JavaScript

var repoindex = (function(repoindex) {
repoindex.softwareUpgradeBackgroundColor = "#dfffdd";
repoindex.packageUpgradeBackgroundColor = "#dde3ff";
repoindex.downgradesBackgroundColor = "#ffeecb";
repoindex.orphanedPackageBackgroundColor = "#fdd";
var PackageEntry = {};
PackageEntry.prototype = new repoindex.Entry();
PackageEntry.prototype.constructor = PackageEntry;
PackageEntry = function(repoEntry, packageName, packageInfo, color) {
this.repoEntry = repoEntry; // might be undefined
repoindex.Entry.prototype.constructor.call(this, packageName, packageInfo);
// init row element
if(color) {
this.rowElement.style.backgroundColor = color;
}
this.rowElement.onclick = function(e) {
repoindex.pageManager.packageManager.showPackageInfoForIndex(this.entry.index, typeof e === "object" && e.button === 1);
};
this.initTableRow = function() {
var basics = this.info.basics ? this.info.basics : {};
var srcOnly = this.repoEntry && this.repoEntry.info.srcOnly;
var pkgOnly = this.repoEntry && this.repoEntry.info.pkgOnly;
var version = this.curVer ? (this.curVer + " → " + (basics.ver ? basics.ver : "?")) : basics.ver;
var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate, pkgOnly ? "n/a" : basics.flagdate];
for(var i = 0; i < 7; ++i) {
this.rowElement.addCell(repoindex.makeStr(values[i]));
}
};
this.initTableRow();
};
repoindex.PackageEntryManager = {};
repoindex.PackageEntryManager.prototype = new repoindex.EntryManager();
repoindex.PackageEntryManager = function(pagination, repoEntries) {
repoindex.EntryManager.prototype.constructor.call(this, PackageEntry, document.getElementById("packages"), pagination, repoEntries);
this.entryName = "package";
this.entryNamePlural = "packages";
this.containerName = "repository";
this.containerNamePlural = "repositories";
this.getContainerQuantity = repoindex.entryManagerGetRepoQuantity;
this.createCustomEntry = function(repoEntry, packageName, packageInfo, color) {
return new PackageEntry(repoEntry, packageName, packageInfo, color);
};
this.addEntry = function(repoEntry, packageName, packageInfo) {
packageInfo.repo = repoEntry.name;
packageInfo.name = packageName;
packageInfo.received = false;
var entry = new PackageEntry(repoEntry, packageName, packageInfo);
entry.index = this.entries.length;
this.entries.push(entry);
return entry;
};
// handle a page selection
this.pagination.pageSelected = function(pageElement) {
var mgr = this.entryManager;
// remove elements from previously selected page
mgr.entryContainer.wipeChildren();
// if there is no page because there are no package entries, pageElement is null
if(pageElement) {
// show elements of selected page
var packageSelection = {}; // package selection for requesting package info
var entriesRequired = false;
pageElement.forRange(function(i) {
var entry = mgr.filteredEntries[i];
entry.add(mgr.entryContainer);
if(!entry.info.basics) {
var repoArray = packageSelection[entry.info.repo];
if(!Array.isArray(repoArray)) {
packageSelection[entry.info.repo] = [{index: entry.info.index, name: entry.info.name}];
} else {
repoArray.push({index: entry.info.index, name: entry.info.name});
}
entriesRequired = true;
}
}, mgr.filteredEntries.length);
var updateTableRows = function() {
pageElement.forRange(function(i) {
mgr.filteredEntries[i].updateTableRow();
}, mgr.filteredEntries.length);
};
if(entriesRequired) {
repoindex.client.requestBasicPackagesInfo(packageSelection, updateTableRows);
}
}
};
this.infoBox = document.getElementById("packages_info");
this.showPackageInfo = function(repo, name, newTab) {
var determineEntry = function() {
var res = repoindex.pageManager.packageManager.entries.filter(function(entry) {
return entry.info.repo === repo && entry.info.name === name;
});
if(res.length > 0) {
repoindex.pageManager.packageManager.showPackageInfoForIndex(res[0].index, newTab);
} else {
repoindex.pageManager.packageManager.showPackageNotFound(repo, name);
}
};
// basic repo info available?
if(repoindex.client.hasBasicRepoInfo) {
// yes -> can determine entry instantly
determineEntry();
} else {
// no -> request info, use callback to determine entry when info becomes available
repoindex.client.requestBasicRepoInfo(determineEntry);
}
};
this.showPackageInfoForIndex = function(entryIndex, newTab) {
// check whether specified entry index is valid
var entry = this.entryByIndex(entryIndex);
if(entry) {
// show properties
var setProperties = function() {
// -> find info container and make info table
var infoContainer = repoindex.pageManager.createPackageInfoPane(entry, newTab);
infoContainer.wipeChildren();
var infoTable = repoindex.makeInfoTable();
var tb = infoTable.tbodyElement;
// -> basic package info
var basics = entry.info.basics ? entry.info.basics : {};
repoindex.addPackageNames(tb, "Name", [entry.name]);
switch(entry.info.repo) {
case "AUR":
repoindex.setLink(repoindex.addField(tb, "Repository"), "AUR", "https://aur.archlinux.org/packages/" + encodeURIComponent(entry.name), window.open, "open AUR page");
break;
case "core":
case "extra":
case "multilib":
case "community":
if(basics.arch) {
repoindex.setLink(repoindex.addField(tb, "Repository"), entry.info.repo, "https://www.archlinux.org/packages/" + entry.info.repo + "/" + basics.arch + "/" + encodeURIComponent(entry.name), window.open, "open Arch Linux page");
break;
}
default:
repoindex.addField(tb, "Repository", repoindex.makeStr(entry.info.repo));
}
repoindex.addField(tb, "Version", repoindex.makeStr(basics.ver));
repoindex.addField(tb, "Description", repoindex.makeStr(basics.desc));
if(basics.arch) {
repoindex.addField(tb, "Architecture", repoindex.makeStr(basics.arch));
} else if(basics.archs) {
repoindex.addField(tb, "Architectures", repoindex.makeArray(basics.archs));
}
// -> full package info
var details = entry.info.details ? entry.info.details : {};
if(details.url) {
repoindex.setLink(repoindex.addField(tb, "Upstream URL"), details.url, details.url, window.open);
} else {
repoindex.addField(tb, "Upstream URL", "unknown");
}
repoindex.addField(tb, "Licenses", repoindex.makeArray(details.lic));
repoindex.addPackageNames(tb, "Groups", repoindex.pack(details.grp), repoindex.Pages.Groups);
repoindex.addPackageNames(tb, "Provides", repoindex.pkgNamesFromDeps(details.prov));
repoindex.addPackageNames(tb, "Dependencies", repoindex.pkgNamesFromDeps(details.deps));
repoindex.addPackageNames(tb, "Optional deps", repoindex.pkgNamesFromDeps(details.optd));
if(details.mkd && details.mkd.length) {
repoindex.addPackageNames(tb, "Make deps", repoindex.pkgNamesFromDeps(details.mkd));
}
if(details.chkd && details.chkd.length) {
repoindex.addPackageNames(tb, "Check deps", repoindex.pkgNamesFromDeps(details.chkd));
}
if(details.requ || details.optf) {
repoindex.addPackageNames(tb, "Required by", details.requ);
repoindex.addPackageNames(tb, "Optional for", details.optf);
}
repoindex.addPackageNames(tb, "Conflicts with", repoindex.pkgNamesFromDeps(details.conf));
repoindex.addPackageNames(tb, "Replaces", repoindex.pkgNamesFromDeps(details.repl));
if(details.bav) {
if(entry.info.repo !== "local") { // local repo does no provide package size
repoindex.addField(tb, "Package size", repoindex.makeDataSize(details.csize));
}
repoindex.addField(tb, "Install size", repoindex.makeDataSize(details.isize));
repoindex.addField(tb, "Packager", details.pack);
repoindex.addField(tb, "Build date", repoindex.makeStr(basics.bdate));
if(entry.info.repo === "local") {
repoindex.addField(tb, "Install date", repoindex.makeStr(details.idate));
repoindex.addField(tb, "Install reason", details.expl ? "explicitly installed" : "installed as dependency");
}
repoindex.addField(tb, "Install script", repoindex.makeBool(details.scri));
repoindex.addField(tb, "Validation methods", repoindex.makeArray(details.sig, ", "));
repoindex.setTree(repoindex.addField(tb, "Package files"), repoindex.makeTree(details.files));
}
if(details.sav) {
if(details.main) {
repoindex.addField(tb, "Maintainer", repoindex.makeStr(details.main));
}
if(basics.flagdate) {
repoindex.addField(tb, "Out-of-date", repoindex.makeStr(basics.flagdate));
}
if(details.fsub) {
repoindex.addField(tb, "First submitted", repoindex.makeStr(details.fsub));
}
if(details.lmod) {
repoindex.addField(tb, "Last modified", repoindex.makeStr(details.lmod));
}
if(details.votes) {
repoindex.addField(tb, "Votes", repoindex.makeStr(details.votes));
}
}
// -> update download buttons
if(details.bav || details.sav) {
var downloadElement = repoindex.addField(tb, "Download");
var spanElement;
if(details.bav) {
spanElement = document.createElement("span");
var downloadPkgParams = {repo: entry.info.repo, pkg: entry.name, down: "pkg"};
repoindex.setDownloadButton(spanElement, "package", repoindex.makeHash(repoindex.Pages.Packages, downloadPkgParams, true), function() {
repoindex.pageManager.denoteHash(repoindex.Pages.Packages, downloadPkgParams);
repoindex.pageManager.packageManager.showMirrorsForIndex(entryIndex);
});
downloadElement.appendChild(spanElement);
}
if(details.srctar && typeof details.srctar === "string") {
spanElement = document.createElement("span");
var downloadSrcParams = {repo: entry.info.repo, pkg: entry.name, down: "src"};
repoindex.setDownloadButton(spanElement, "source", repoindex.makeHash(repoindex.Pages.Packages, downloadSrcParams, true), function() {
repoindex.pageManager.denoteHash(repoindex.Pages.Packages, downloadSrcParams);
window.open("https://aur.archlinux.org" + details.srctar);
});
downloadElement.appendChild(spanElement);
}
}
infoContainer.appendChild(infoTable.tableElement);
};
setProperties();
if(!entry.info.basics || !entry.info.details) {
// don't have the full package info yet -> request full package info
var packageSelection = {};
packageSelection[entry.info.repo] = [{index: entryIndex, name: entry.name}];
repoindex.client.requestFullPackagesInfo(packageSelection, setProperties);
}
// set currentInfo (the pageManager needs this value to upgrade the hash)
this.currentInfo = entry.info;
// ensures, that the "Package Info" box (with the properties just set) is shown
repoindex.pageManager.showPackageInfo(true);
}
};
this.showMirrors = function(repo, name) {
var determineEntry = function() {
var res = repoindex.pageManager.packageManager.entries.filter(function(entry) {
return entry.info.repo === repo && entry.name === name;
});
// entry exists?
if(res.length > 0) {
// yes -> full package info available?
var entry = res[0];
var showEntry = function() {
repoindex.pageManager.packageManager.showMirrorsForIndex(entry.index);
};
if(entry.info.details) {
// yes -> show entry instantly
showEntry();
} else {
// no -> request full info, use callback to show entry when info becomes available
var packageSelection = {};
packageSelection[entry.info.repo] = [{index: entry.index, name: entry.name}];
repoindex.client.requestFullPackagesInfo(packageSelection, showEntry);
}
} else {
// no -> show error
repoindex.pageManager.packageManager.showPackageNotFound(repo, name);
}
};
// basic repo info available?
if(repoindex.client.hasBasicRepoInfo) {
// yes -> can determine entry instantly
determineEntry();
} else {
// no -> request info, use callback to determine entry when info becomes available
repoindex.client.requestBasicRepoInfo(determineEntry);
}
};
this.showMirrorsForIndex = function(entryIndex) {
var entry = this.entryByIndex(entryIndex);
if(entry) {
var info = entry.info;
repoindex.setText("title_mirror_selection", "Mirrors for package <i>" + repoindex.escapeHtml(entry.name) + "</i>", true);
var listMirrorSelection = document.getElementById("list_mirror_selection");
listMirrorSelection.wipeChildren();
var repoEntries = repoindex.pageManager.repoManager.entries.filter(function(entry) {
return entry.name === info.repo;
});
var mirrorsAvailable = 0;
if(repoEntries.length > 0) {
var mirrors = repoEntries[0].info.servers;
if(Array.isArray(mirrors) && mirrors.length > 0) {
for(var i = 0; i < mirrors.length; ++i) {
var liElement = document.createElement("li");
var aElement = document.createElement("a");
var url = mirrors[i] + "/" + info.details.file;
aElement.appendChild(document.createTextNode(url));
aElement.href = url;
aElement.onclick = function() {
window.open(this.href);
return false;
};
liElement.appendChild(aElement);
listMirrorSelection.appendChild(liElement);
}
mirrorsAvailable = 1;
}
}
}
if(mirrorsAvailable !== 1) {
// no mirrors available?
if(info.repo === "local" || info.repo === "LOCAL") {
// no surprise because its an package from the local database
mirrorsAvailable = -1;
} else if(info.repo === "aur" || info.repo === "AUR") {
// no surprise because its an AUR package
mirrorsAvailable = -2;
}
}
if(mirrorsAvailable === 1) {
repoindex.setText("status_mirror_selection", "Select a mirror:");
} else if(mirrorsAvailable === -1) {
repoindex.setText("status_mirror_selection", "The package belongs to the <i>local</i> database. Hence there are no mirrors available.", true);
} else if(mirrorsAvailable === -2) {
repoindex.setText("status_mirror_selection", "The package is from the <i>Arch Linux User Repository</i>. Hence there are no mirrors available.", true);
} else {
repoindex.setText("status_mirror_selection", "No mirrors available.");
}
$("#dlg_mirror_selection").modal("show");
};
this.showPackageNotFound = function(repo, name) {
repoindex.pageManager.msgboxCritical(
"Package not found",
"The package <i>" + repoindex.escapeHtml(name) + "</i> can not be found in the repository <i>" + repoindex.escapeHtml(repo) + "</i>.",
true);
};
}
return repoindex;
})(repoindex || {});