-
-
Notifications
You must be signed in to change notification settings - Fork 345
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
Fixes for GUI and .ckan-installed modules #3307
Conversation
ff56534
to
a32bbff
Compare
a32bbff
to
3812954
Compare
3812954
to
ea79ee0
Compare
Heh, you really love your custom .ckan files, don't you? 😆 |
(Wow; the example code in the documentation of IsBusy, instead of noting that it may be needed to avoid the world's dumbest |
Guess so 😄 |
I noticed that the change set clearing logic also doesn't work for forced installs of incompatible modules, since |
47ee20b
to
b316cdf
Compare
I might have found a way to achieve this.
I also gave modules queued for removal because they have been marked as auto installed a stab. I've seen users checking this checkbox without knowing what it does, then despairing because CKAN wants to remove their mods. This doesn't catch modules that still have dependent mods, but it's impossible to know their previous state. And they shouldn't be much of a problem anyway, since they aren't about to be removed. |
* Append installed mod version in `AllModVersions` tab if not known to registry (e.g. if installed from local .ckan) * Don't mark .ckan-installed mods as incompatible * Add OK button to wait tab page; it is enabled if the install process failed or the user cancelled too late. When clicked it hides the tab and calls `UpdateModsList()` to clear/update the changeset. * Remove queued changes of incompatible modules and from the changeset when clearing changeset * Remove queued removals for mods whose AutoInstall checkbox has been checked without dependent mod installed when clearing changeset * Prevent `installWorker` from being run twice if a user double-clicks the "Accept" button * Make `menuStrip2` overflowable * Fix opening instance directory in `ManageGameInstancesDialog` * Don't offer upgrades that would violate other modules' dependencies * Prevent `NullReferenceException` in `NetAsyncDownloader.FileProgressReport()`
In 'IRegistryQuerierHelpers.HasUpdate()' and 'ModuleInstaller.CanInstall()' we didn't pass the currently installed module version as 'moduleToRemove', thus the RelationshipResolver couldn't detect if another mod depending on a specific version of a mod would break. This made the GUI offer upgrades that would fail during the actual installation, and the 'Versions' tab listing versions as compatible that weren't.
b316cdf
to
91c2071
Compare
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.
Nice! Good stuff all around.
@@ -194,7 +194,7 @@ public static bool HasUpdate(this IRegistryQuerier querier, string identifier, G | |||
{ | |||
RelationshipResolver resolver = new RelationshipResolver( | |||
new CkanModule[] { newest_version }, | |||
null, | |||
new CkanModule[] { querier.InstalledModule(identifier).Module }, |
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.
This one broke upgrading AD mods, InstalledModule()
is null
for those, thus we get an exception which caught below and returns false
.
The easy fix is to pass no array if it's a DLL. However since DLLs are considered to satisfy all dependencies, it's still possible that an upgrade would fail if the new version violated a versioned dependency.
The cleaner way would be to track installed DLLs separately in RelationshipResolver
, and give the constructor a new option to tell the DLLs that are about to removed.
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.
This one broke upgrading AD mods
Maybe we need some tests for that. It seems a bit brittle at the moment.
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.
By pure luck, adding a ?
also works, because RelationshipResolver
is conservative with nulls:
new CkanModule[] { querier.InstalledModule(identifier)?.Module },
The cleaner way would be to track installed DLLs separately in
RelationshipResolver
, and give the constructor a new option to tell the DLLs that are about to removed.
I wonder whether AD mods should have their own InstalledModule
, possibly with a CkanModule
with "kind": "dll"
?
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 wonder whether AD mods should have their own
InstalledModule
, possibly with aCkanModule
with"kind": "dll"
?
Interesting idea. I'm a bit anxious that things might break if they expect InstalledModule()
to only return CKAN-managed modules. And if InstalledModule()
returns modules that aren't in InstalledModules
, more things might get confused (or would we also include DLLs in InstalledModules
?)
And remembering all the bugs we had to fix because we didn't filter out "kind": "dlc"
...
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.
And remembering all the bugs we had to fix because we didn't filter out
"kind": "dlc"
...
Yes, it's definitely a high risk change. For now, I think I'm going to try writing that test and doing the easy fix.
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.
And I'm currently trying out tracking DLLs separately in the RelationshipResolver, so far it brought up some more places where we missed to pass all the data we should've to the resolver.
But since it basically includes the easy fix anyway, I think it's good that you do it as a separate PR, especially if it contains some tests that help catching any problems with more complex changes.
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.
especially if it contains some tests that help catching any problems with more complex changes
Heh, I was just going to do the one simple test of HasUpdate
with an AD mod, but now I'm looking for a few more...
- CKAN offers to upgrade modules even if it would violate another module's relationships
Do you remember which relationships these were? Did another installed module have a depends
with version
?
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.
Do you remember which relationships these were? Did another installed module have a
depends
withversion
?
Yup, BeyondHome with Parallax: KSP-CKAN/NetKAN#8378
And this one is also interesting since I've read from a lot of people having Parallax installed manually, because for all they knew the installation via CKAN was broken, and sometimes because they didn't know of the downgrade functionality. So that got me into the whole AD and upgrade with unsatisfied dependency rabbit hole.
Problems:
GUI
AllModVersiions
tab. Neither does it remove mods queued for removal because they've been checked as auto-installed without any dependent mods.ConsoleUI
CKAN-ConsoleUI.exe
directly (e.g. via IDE), you get an exception because thethemename
passed toConsoleCKAN()
isnull
.Core
VersionsListView
as installable.NetAsyncDownloader.FileProgressReport()
, for thet
variable in thequeuedDownloads
foreach-loop. Unfortunately KDE crashed some time later and I didn't save the stacktrace to disk yet.Causes:
GUI
We don't run
UpdateModsList
after the install process has been cancelled, thus the changeset doesn't get cleared. We can't run it immediately, because it would close the WaitTabPage and remove the useful log messages.ClearChangeSet()
doesn't detect changes for incompatible mods sinceIsInstallChecked
isfalse
for them.GetModChanges()
find it by comparingGUIMod.SelectedMod
withGUIMod.InstalledMod.Module
.And it doesn't know about the auto-installed modules because toggling the chexkbox isn't an action itself that gets added to the changeset – it's applied instantly by setting
InstalledMod.AutoInstalled
.If you manage to hit the "Accept" button again before the GUI switches to the WaitTabPage, it tries to call
installWorker.RunWorkerAsync()
a second time, throwing the exception.AllModVersions
usesregistry.AvailableByIdentifier(value.Identifier)
to populate theVersionListView
. If the registry can't find anything, we just return, even without clearing the existing version items from the previous mod.GUIMod.IsIncompatible
is alwaystrue
for unknown modules becauseregistry.LatestAvailable()
can't find anything.https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.menustrip.canoverflow?view=net-5.0#System_Windows_Forms_MenuStrip_CanOverflow
Core
DownloadTarget
can becomenull
.Changes
GUI
UpdateModsList()
runs at some point. The tabController stays locked and the top menu deactivated until the user hits "OK". This means we also need to unlock the tabController when cancelling earlier in the installation process like when selecting the recommendations/suggestions or provides, because we never show the FailWaitDialog in this case.ClearChangeSet()
also comparesSelectedMod
andInstalledMod
now, and does the reverse ofGetModChanges()
, i.e. settingSelectedMod
back toInstalledMod
if they differ.SelectionReason.NoLongerUsed
, and if so, sets it to false again. Doesn't catch all mods whose checkbox got changed, but it should suffice for most cases, to clear the changeset.installWorker
is already running, don't run it a second time. This was easier than trying to disable the button and finding all the right places where we'd need to enable it aǵain.CkanModule
associated with theGUIModule
to the list, if it exists.GUIMod
constructor that takes anInstalledModule
as arg now overwritesIsIncompatible
based on the compatibility of the installed module.menuStrip2
overflowable. Instead of just not drawing the buttons, there's now a small dropdown to list those that didn't fit anymore. Doesn't work on Mono (it behaves just like before), but on Windows:ConsoleUI
themeName
passed toConsoleCKAN
isnull
it falls pack todefault
.Core
RelationshipResolver
instantiations inModuleInstaller.CanInstall()
andIRegistryQuerierHelper.HasUpdate()
now pass the currently installed module (if any) asmoduleToRemove
, just like the resolver for the actual install process does.null
check in the two foreach-loops inNetAsyncDownloader.FileProgressReport()
and skip ift
isnull
.