-
-
Notifications
You must be signed in to change notification settings - Fork 529
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
[Package Manager] Re-Download missing packages #14018
base: 3.x
Are you sure you want to change the base?
Conversation
cherry-picked from modxcms#13979
Was surprised that the package manager is not able to re-download packages in case the zip files / extracted folders are missing for an installed package (for whatever reason, in my particular case did I want to save space for backups and did not include the packages folder...). When trying to re-install a package with missing files it would proceed to the installation (of course without metadata displaying), then when hitting "Continue" show the modal and say could not download the package etc., but it never actually tried to re-download... This PR changes that so if the zip file is not present, it would actually try to re-download it. There is an edge case where the package is not available anymore on the provider (for example I had an old version of the "console" extra that was not available anymore) and the provider would return an error code (e.g. 404 in that case), but the old code would actually "package" the response HTML or JSON code into a .zip file and then of course the installation would fail with "could not unpack package"...This PR also solves that issue by handling error codes from the provider. Although not used very often, I did rewrite large parts of the _getByFsockopen() method as it needed some love.
If anybody knows a better way to get a packages download link than (without making an unnecessary remote request) $location = $this->get('metadata')[array_keys(array_filter($this->get('metadata'), function($item) { if ($item['name'] === 'location') { return $item; } }))[0]]; please let me know, happy to change that monster... And of course it would be nice if the frontend would inform the user about whats happening before he hits "Continue/Install" and then gets the error, but not sure how to add that... |
I do not know how the lookup is structured in
I would split this expression into a method instead and do each step seperate. Here the code is a bit too confusing to just read out. You also seem to use |
@OptimusCrime added your multiline suggestion, I'd like to avoid creating new methods for something "that trivial", as far as I can see if a package is installed it will always have the location in the metadata, so there should be no need for a remote request. The problem is, that the metadata is horribly structured to say the least, its an array with numeric keys, so the location was at index 28 in my case, but I don't want to rely on that index to be always the same, therefore the // loop trough metadata arrays until location is found
$locationarr = array_filter($this->get('metadata'), function($item) {
if ($item['name'] === 'location') {
return $item;
}
});
// determine the index at which the location metadata was found
$locationkey = array_keys($locationarr)[0];
// get the location metadata
$location = $this->get('metadata')[$locationkey]; will update like that for now. |
Hopefully slightly more readable, also added comments.
Switch comment style to the one used in the rest of the file. Also make sure that if there is a package directory it is checked that it has files in it, I occasionally have the scenario when that directory is there, but its empty, then the package re-unpack fails and so does the installation of the package.
/* not very pretty way of getting the download URL, but otherwise we have to make a | ||
* remote request to $this->Provider->info($this->signature) to get the URL. | ||
* loop trough metadata arrays until location is found */ | ||
$locationarr = array_filter($this->get('metadata'), function($item) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To maintain readability I suggest using the camelCase naming convention for variable names.
Nice work! Just to be sure, did you sign the Contributor License Agreement? |
Following the advice from @OptimusCrime, I added a more generic getMetadata() method to the class, like this any other metadata can also be accessed more easily in case its ever needed.
Separated the metadata code into a separate, more generic method /**
* Get metadata for a package in a more usable format
*
* @return array an array of metadata accessible by metadata name field
*/
public function getMetadata() {
$metadata = array_reduce($this->get('metadata'), function ($result, $item) {
$key = $item['name'];
unset($item['name']);
$result[$key] = $item;
return $result;
}, array());
return $metadata;
} That method will return an array in the form of:
that reduces the code within /* make sure the package is downloaded, if not attempt re-download */
if (strpos($sourceFile, '//') === false && !file_exists($targetDir . $sourceFile)) {
/* get the package metadata */
$metadata = $this->getMetadata();
if (!empty($metadata) && $metadata['location']) {
/* assign remote download URL */
$source = $metadata['location']['text'];
}
} Need some help with the sprintf() thingy, not sure how you would do that optimization. @JoshuaLuckers signed the contributor agreement years ago =) |
When updating a package it would also trigger the re-download logic (as package file not present yet) and re-assign the `$sourceFile` variable passed to `transportPackage()` which would cause it to fail. Therefore it is now checked if the `$sourceFile` variable contains a URL already, if that's the case, the re-download logic is skipped. When triggering a re-install action from the manager the `$sourceFile` variable is set to the package string and not a URL like when an update is triggered.
Not sure if we use sprintf that much in the core. I usually just see string concatenation like you have already done. |
Another update, did the direct return as suggested but also found some strange edge cases with an installation I have:
There is an edge case I couldn't solve: Missing dependencies (like resizer for pThumb) are not properly re-downloaded, I had to delete the package via manager first, then re-install pThumb to make it work...don't know why^^, not familiar enough with the dependency feature of the package manager. |
Just one thing. Could this PR target 2.x? |
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7", | ||
"Keep-Alive: 300", | ||
"Connection: keep-alive", | ||
"Referer: http://$host", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it has any influence on how the code works but just to be consistent it would be nice if the referer would use the same protocol (http or https) as the "host".
also changed referrer URL scheme
@Jako just changed the base to 2.x, is that the proper way of targeting PRs? It seems it kind of messes up the PR a bit, there are now 10 changed files (probably because the PR was based on 2.6.5) instead of just one...do I need to resolve that by re-doing the PR based on the 2.x branch? @JoshuaLuckers changed the way of returning metadata according to your suggestion and added the proper URL scheme to the referrer, guess that's the right way:
? |
Looks fine to me! After you changes the target you have some conflicts that need to be solved. Best way to fix it is to create a new branch with your changes. Revert the current branch to the latest commit from 2.x and cherry pick your changes on to the current branch and force push them. |
I am not sure, if it is the case. It should be possible to redownload every package, not only missing ones. |
@JoshuaLuckers — Don't fear the rebase! ;) |
@Jako A general Re-download feature would be another story, this is simply about fixing a broken "Re-install" functionality in case there is no zip-file present in the packages directory (or the unpacked folder is empty)... regarding the branch mess, was that really necessary (to change the target branch to 2.x)? Switched back to the original 2.6.x for now... |
@exside please accept @JoshuaLuckers suggestion and merge conflict. |
Co-authored-by: Joshua Lückers <joshualuckers@me.com>
Thank you for your contribution! Before your pull request can be reviewed, please sign the MODX Contributor License Agreement (CLA). This is to make sure MODX has your written permission to distribute projects containing your contributions under the appropriate license. Please make sure the CLA has been signed for GitHub user(s): @exside Once you've signed, please reply with |
I have commited the changes of @JoshuaLuckers here. |
@cla-bot check |
The cla-bot has been summoned, and re-checked this pull request! |
Typically you'd need to do a rebase + force push. If that's not feasible or complex, manually applying changes In a new branch is sometimes easier. |
There are 31 commits in this PR. It needs to be reapplied manually on top of latest. It seems someone merged other work into this PR branch. |
Was surprised that the package manager is not able to re-download packages in case the zip files / extracted folders are missing for an installed package (for whatever reason, in my particular case did I want to save space for backups and did not include the packages folder...). When trying to re-install a package with missing files it would proceed to the installation (of course without metadata displaying), then when hitting "Continue" show the modal and say could not download the package etc., but it never actually tried to re-download...
What does it do?
This PR changes that so if the zip file is not present, it would actually try to re-download it. There is an edge case where the package is not available anymore on the provider (for example I had an old version of the "console" extra that was not available anymore) and the provider would return an error code (e.g. 404 in that case), but the old code would actually "package" the response HTML or JSON code into a .zip file and then of course the installation would fail with "could not unpack package"...This PR also solves that issue by handling error codes from the provider.
Although not used very often, I did rewrite large parts of the _getByFsockopen() method as it needed some love.
Why is it needed?
See above.