Writing an updater for my game and reached the point where I would need to scrub the project of old files and folders after update.
I currently use gradle to write a version file for the update process so I thought that may be a good place to write another file that has the desired final state of the project after update.
I could then use walkFileTree to scrub files and directories. Problem is that this doesn’t work for testing other than in the distributed project since that has nothing but the game related files.
I toasted the project once using recursion and an infinite loop that was caused by improper design using relative paths. Basically, I screwed up and set a path that allowed things to move outside the target directory and didn’t realize it till it was to late. In a split second I had a nicely compacted project with every file in it inside one folder. Git saved the project but if that was a delete and it kept going I would of been toast.
I am looking for suggestions on how best to safely approach this so I could test it with the sdk as well as the project itself.
I use lots of logging while building so I can watch the flow but even then things can go wrong very quickly.
Sure, after update the project would have the old jar version still or if a directory or file was renamed then the project needs to be cleaned so it matches the original.
Edit: update only updates changed files or folders in other words.
This is on the client’s machine or your development machine? I assume the former because the latter seems like “gradle clean” to me.
If the former then we might need to know what kind of auto-updater thing you are using. If it’s not homegrown then it may already cover this. And if it is homegrown, it seems like you should have old manifests that you can look at to see what to delete.
All work takes place in the fetched and updates folders. fetched is for the updater files, updates is for the GameClient.
I mimic this in the sdk by just having extracting the Updater into the root folder of the GameClient project. Works great unless I screw up a path and things travel outside the Updater folder.
My own updater.
So far I just use gradle to add a file to the distribution zip in the appropriate place. An example looks like this.
The GameClient version file has alot more files. In either case I download the bin folder if anything at all changes.
I strip the versioning from the zip file name so the file directory structure matches the project and that makes things big time easier since I can just use standard list comparison methods.
I would argue strongly that you never want to delete * anything on a user’s computer. You should only be deleting things you specifically know that you put there.
If the answer is “But I wasn’t tracking that before” then you provide documentation on how you can clean up previous versions. With lots of promises about how you are properly tracking this now.
That way you avoid accidentally deleting their doctoral dissertation or something because they accidentally stored it in your directory and never realized. Modern apps make it super easy to ignore where things are actually stored.
Edit: and then going forward, you need to keep a manifest of things that went into previous updates that are no longer in current updates. However that happens. Those are the things you are allowed to delete.
This means I have the old one prior to update for comparison so I can easily sort it for changes. I guess what you’re saying is stick to only those changes and leave everything else alone just for safety. This makes sense. I hadn’t thought of that.
I cant test download the GameClient or any test app except by extracting the distribution every test since the folder structure overlaps the sdk project structure. I can for the updater since its contained in the Updater folder. I was hoping there was some design that would allow me to test both. Extracting zip can be done with the build process using gradle but its a pain and I still have to disable things to continue further developement after the updater is done.
The design of updaters is common so trying to see how they test these without destroying things or jumping through so may hoops to test it.
The way the updater works it checks first if a new updater has downloaded, if so moves that to its proper folders starts it and exits.
If no new updater, it checks to see if theres a new update for itself, if so, it just starts the updater and exits. Updater downloads and overwrites the Client and starts it again.
Thats where things can lead to trouble. One app starts another. I figured out how things went wrong but that was after there was a problem I didnt forsee. Would like to quarantine this next phase somehow because its deleting things.
For the kinds of things that you are doing, it sounds like you would be better of testing your automated updates, etc, on an independent installation. I.E. Do all of your unit tests, etc in the SDK as usual, then install your app just like a user would, outside of the SDK. Use this installation to test your updater.
Thats what I do. I would rather test it in a sandbox environment. Even when installed it can be dangerous until debugged. Recursion in conjunction with a possible continuous loop is very dangerous.
Since one app starts another app and the apps rely on something being inside a folder to start, things can go bad real fast. The final product is safe but I found that getting to the final product can be harder than it looks.
Following Pauls advice of only deleting known quantities will make things easier and much safer though so I am feeling more confident on using my machine to test it.
Edit: It safer because I have a finite list and can test for the existence of the target whereas before I was intending to do a sync type delete where anything other than the final state is removed.
Reminds of when a friend a looong time ago told me a story about the day he tried to remove a file from his root directory that started with #. rm -rf /#somefile
…it had ground way too long before he noticed his error.