-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues with dependency logic in Util::addScript
#30278
Comments
I opened #30279 as a first attempt to fix this. |
|
So unfortunately there's still issues with the See #30369. |
IMO that raises a red flag. Explicit order dependencies were added. Shouldn't the apps that depend on files now specify their dependency of files? That was the idea of it, right? |
Because those apps should just update and specify that they need their scripts loaded after? |
I agree with you both. And I just realized that the whole dependency order logic is still flawed. Now the problem is, that I spent another few hours with thinking and trying and by now I accepted that I won't find a cheap and simple way to sort the associative array Let's try a (probably incomplete) description of the problem we face:
So let's have a look at the problem "app and dependeny both already in sorted list, but wrong order":
Well, I guess I just described a theoretical problem of each dependency solving algorithm 😬 |
The best I could come up with so far, is an algorithm that works as described above. In case of the "app and dependency both already in sorted list, but wrong order", it chooses "move dependency before the app". That implementation passes the unit tests and all manual testing that broke earlier (different subsets of collectives and deck app enabled and browsing files, collectives and deck app respectively). So it's certainly better than what we had so far, but probably not perfect: $sortedScripts = [];
foreach (array_keys(self::$scripts) as $app) {
$dep = self::$scriptDeps[$app] ?? false;
if (!array_key_exists($app, $sortedScripts)) {
// app not listed yet
if ($dep && !array_key_exists($dep, $sortedScripts)) {
// add dependency if defined and not listed
$sortedScripts[$dep] = self::$scripts[$dep] ?? [];
}
$sortedScripts[$app] = self::$scripts[$app];
} elseif ($dep) {
// app listed and dependency defined
$appPos = array_search($app, array_keys($sortedScripts), true);
$depPos = array_search($dep, array_keys($sortedScripts), true);
if ($depPos !== false) {
if ($appPos < $depPos) {
// app and dependency listed, but wrong order
// -> move dep before app by slicing and merging array
$depScripts = $sortedScripts[$dep];
$withoutDepScripts =
array_slice($sortedScripts, 0, $depPos - 1, true) +
array_slice($sortedScripts, $depPos - 1, NULL, true);
$sortedScripts =
array_slice($withoutDepScripts, 0, $appPos, true) +
[$dep => $depScripts] +
array_slice($withoutDepScripts, $appPos, NULL, true);
}
} else {
// app listed, dependency not
// -> insert dependency before app by slicing and merging array
$sortedScripts =
array_slice($sortedScripts, 0, $appPos - 1, true) +
[$dep => self::$scripts[$dep] ?? []] +
array_slice($sortedScripts, $appPos - 1, NULL, true);
}
}
}
// sort core first
$scripts = array_merge($sortedScripts['core'] ?? [], ...array_values($sortedScripts));
// Flatten array and remove duplicates
return array_unique($scripts); |
Use a topological sort algorithm. It solves your Problem with the ordering. |
I was a bit reluctant to add a PHP dependency for this, but seems like https://github.com/marcj/topsort.php is nice and clean. Shall we use it? I could give it a try. But I didn't contribute much to the server code yet (still kind of a newbie here 😉), and to be honest I don't feel confident enough to take such a decision. Also, performance is really critical here, as |
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278
I couldn't resist and implemented a stripped down version of https://github.com/marcj/topsort.php: #30385 Related unit tests and manuall tests pass 🎉 |
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Throws a CircularDependencyException if a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
Implement a proper topological sorting algorithm. Based on the implementation by https://github.com/marcj/topsort.php Logs an error in case a circular dependency is detected. Fixes: #30278 Signed-off-by: Jonas Meurer <jonas@freesources.org>
The new dependency logic as implemented in #30015 is broken if dependencies themselves have dependencies. E.g. when text app depends on viewer and viewer depends on files, the script from text is loaded first while the script from viewer comes later:
The problem is that the
files
dependency ofviewer
movesviewer/js/viewer-main
to thelast
element offiles
, while theviewer
dependendy ontext
movestext/js/text-viewer
to thelast
element ofviewer
. Viewer is before files butviewer
no longer containsviewer/js/viewer-main
, so loadingtext/js/text-viewer
fromlast
fails.self::$scripts
fromserver/lib/public/Util.php
Line 243 in 791d570
After removing
files
dependency fromviewer
(in https://github.com/nextcloud/viewer/pull/1081/files#diff-a14aae69340720190ddf327b54675eacd97116b45f5b57f583ddb52829a3f152R41):So I guess we need to improve the logic and sort scripts by dependencies.
The text was updated successfully, but these errors were encountered: