Skip to content
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

Provides updated PackageManager architecture #452

Merged
merged 20 commits into from
Nov 3, 2019

Conversation

praj-foss
Copy link
Member

@praj-foss praj-foss commented Aug 17, 2019

Summary

Provides an improved architecture for the PackageManager, adding features to support multiple online repositories and better handling of game packages. Fixes #451.

This architecture was inspired by classic Linux package managers like apt and pacman. The design was originally planned as shown in this diagram:
pkgmgr2

Testing

Coming soon

Outstanding before merging

  • Add PackageDatabase support
  • Handle repositories mentioned in a local file
  • Write/read the database to/from a local file
  • Handle multiple repository types
  • Integrate with old codebase and PackageManager

- PackageDatabase works with repositories mentioned in a file
- Adds methods to sync, load and save PackageDatabase
- Adds RepositoryHandlers for handling Jenkins and custom repositories
@praj-foss praj-foss self-assigned this Aug 17, 2019
@praj-foss praj-foss added this to the v4.0.0 - GSOC 2019 milestone Aug 17, 2019
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- Package names need to be mentioned in sources.json file for tracking
- Packages contains location field for locating their ZIPs
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- Presents database as a list of package instances
- Package instances provide isInstalled() method
- Changes some PackageManager and RespositoryHandler methods for consistency
- Replaces TerasologyGameVersions instances with PackageManager in controllers
- Minor changes to PackageManager API
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- Uses DownloadUtils and FileUtils inside PackageManager to download and extract packages
- Provides DownloadTask inside ApplicationController to observe installation progress
- Moves directory name strings from PackageDatabase to PackageManager
- PackageDatabase detects installed packages during sync()
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- Modifies GameStarter to start games installed via PackageManager
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- PackageManager directly installs the cached package if available
- Disables combo-boxes while downloading
- PackageManager removes specified game package
- Defines DeleteTask to perform delete operation asynchronously
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

- Copies the supplied sources.json file when it's absent in the local filesystem
- Changes config directory structure
- Removes all toAbsolutePath() calls during logging in PackageDatabase
- Prevents download button from getting buggy after closing settings menu
- Binds package and version combo-boxes of both the controllers
@GooeyHub
Copy link
Member

Hooray Jenkins reported success with all tests good!

@GooeyHub
Copy link
Member

GooeyHub commented Nov 2, 2019

Hooray Jenkins reported success with all tests good!

The utility methods for directories are very specific for the launcher
and even contain constants for the data directory name, cache directory,
or application directory name.
The new name should indicate this dedicated purpose.

`FileUtils` are more general and not tightly coupled to launcher
functionality. Some methods might be moved there in the future.
This is a replacement for `FileUtils.deleteDirectoryContent` which
additionally ensures that the directory exists and is empty.
The old method has been made private and is still used internally.

- updated call to use `ensureEmptyDir`
- added tests for `ensureEmptyDir`
…ls.ensureWritableDir`

- introduce `LauncherManagedDirectory` enum for directories local to launcher installation path
- introduce `DirectoryCreator` functional interface
- refactor `getXYZDirectory` methods in the init task
  - make use of managed directory enum
  - make use of DirectoryCreator interface via method references
  - unify directory creation and error handling
@GooeyHub
Copy link
Member

GooeyHub commented Nov 2, 2019

Uh oh, something went wrong with the build. Need to check on that

@GooeyHub
Copy link
Member

GooeyHub commented Nov 2, 2019

Hooray Jenkins reported success with all tests good!

- use `!Files.exists(dir)` instead of `Files.notExists(dir)` like in ensureWritableDir
- add `Files.isDirectory(dir)` check
@GooeyHub
Copy link
Member

GooeyHub commented Nov 3, 2019

Hooray Jenkins reported success with all tests good!

Comment on lines +164 to +166
if (!Files.isDirectory(directory)) {
throw new IOException("Directory is not a directory! " + directory);
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure, if we want to put that here.
deleteDirectoryContent will throw a NotDirectoryException on calling Files.list(directory) if directory is not a directory. While this should be a well-understandable exception, I think it makes sense to check before-hand.
I put the check into ensureEmptyDir to align it with ensureWritableDir which includes this check as well, but maybe it would be better off in deleteDirectoryContent...
@praj-foss @skaldarnar what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a revisit anyways. Some notes on the current state and where it might be headed:

  • Files.createDirectories(path) will create directory (if possible) or return the directory if it exists. If it is no directory, it will throw an exception - pretty much what we are trying to do as a first step here and in ensureWritableDir. Maybe we can make better use of it.
  • I'm not really happy with the void return types and the exceptional behavior. Maybe we can hide that and instead expose Optional<Path> or the like for internal usage (as abstraction over the underlying file system operations).
  • Seems like we are building this up in multiple steps: (1) ensure directory exists, (2) ensure directory is writable, (3) ensure directory is empty, ... Not sure how we could build a nice functional interface for that, or whether it is actually worth it 🙄
  • ... and file attributes: https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/package-summary.html 🤷‍♂

@GooeyHub
Copy link
Member

GooeyHub commented Nov 3, 2019

Uh oh, something went wrong with the build. Need to check on that

@GooeyHub
Copy link
Member

GooeyHub commented Nov 3, 2019

Hooray Jenkins reported success with all tests good!

Copy link
Member

@skaldarnar skaldarnar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@praj-foss @jdrueckert Left a bunch of comments such that we know where to continue 😉 Will hit that green button now and finally merge it, should make it easier to progress in smaller steps towards a new release.

private Path getLauncherDirectory(OperatingSystem os) throws LauncherStartFailedException {
logger.trace("Init LauncherDirectory...");
final Path launcherDirectory = DirectoryUtils.getApplicationDirectory(os, DirectoryUtils.LAUNCHER_APPLICATION_DIR_NAME);
private void initDirectory(Path dir, String errorLabel, DirectoryCreator... creators)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole set of methods dealing with directory creation, initialization, etc need to get a revisit. Cleaning up naming, adding Javadoc, refactoring (more) common code.

@@ -285,20 +275,6 @@ private Path getGameDataDirectory(OperatingSystem os, Path settingsGameDataDirec
return gameDataDirectory;
}

private TerasologyGameVersions getTerasologyGameVersions(Path launcherDirectory, Path gameDirectory, BaseLauncherSettings launcherSettings) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether this should be removed already (@praj-foss ?). I just threw it out because it was not used... Can re-add it easily from Git history if needed, though.

@@ -93,7 +93,7 @@ public synchronized TerasologyGameVersion getGameVersionForBuildVersion(GameJob
}

public synchronized void loadGameVersionsFromPackageManager(GameSettings gameSettings, Path launcherDirectory, Path gameDirectory) {
final Path cacheDirectory = launcherDirectory.resolve(DirectoryUtils.CACHE_DIR_NAME);
final Path cacheDirectory = launcherDirectory.resolve(LauncherDirectoryUtils.CACHE_DIR_NAME);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all the launcher managed directories should be retrieved from the config/settings object, instead of resolving the path again and again.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with that.. It should look more sensible to have the PackageManager directly depend on the settings object and resolve all required paths itself.

@@ -89,20 +90,100 @@
private static final long MB = 1024L * 1024;
private static final long MINIMUM_FREE_SPACE = 200 * MB;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should more wide be used, or thrown out 🤔 maybe even a combination of (a) minimum absolute free space (e.g., 200mb) and (b) not more than 95% of disk space used...

@@ -89,20 +90,100 @@
private static final long MB = 1024L * 1024;
private static final long MINIMUM_FREE_SPACE = 200 * MB;

private static final class DownloadTask extends Task<Void> implements ProgressListener {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely needs Javadoc, and should probably live in its own class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for Javadoc.. But won't this task be better encapsulated as an inner class, if it's not supposed to be used outside of ApplicationController?

/**
* Provides method to fetch all packages from a repository.
*/
interface RepositoryHandler {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a @FunctionalInterface?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes I really forget that I'm on Java 8 😅

/**
* Functional interface to abstract over directory creation.
*/
public interface DirectoryCreator {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have @FunctionalInterface annotation

Comment on lines +164 to +166
if (!Files.isDirectory(directory)) {
throw new IOException("Directory is not a directory! " + directory);
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a revisit anyways. Some notes on the current state and where it might be headed:

  • Files.createDirectories(path) will create directory (if possible) or return the directory if it exists. If it is no directory, it will throw an exception - pretty much what we are trying to do as a first step here and in ensureWritableDir. Maybe we can make better use of it.
  • I'm not really happy with the void return types and the exceptional behavior. Maybe we can hide that and instead expose Optional<Path> or the like for internal usage (as abstraction over the underlying file system operations).
  • Seems like we are building this up in multiple steps: (1) ensure directory exists, (2) ensure directory is writable, (3) ensure directory is empty, ... Not sure how we could build a nice functional interface for that, or whether it is actually worth it 🙄
  • ... and file attributes: https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/package-summary.html 🤷‍♂


public static final String LAUNCHER_APPLICATION_DIR_NAME = "TerasologyLauncher";
public static final String GAME_APPLICATION_DIR_NAME = "Terasology";
public static final String GAME_DATA_DIR_NAME = "Terasology";
public static final String DOWNLOAD_DIR_NAME = "download";
public static final String TEMP_DIR_NAME = "temp";
public static final String CACHE_DIR_NAME = "cache";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be removed .... thought I did it, now have to do it later 😅

@@ -75,6 +75,7 @@ message_error_loadSettings=
message_error_operatingSystem=
message_error_storeSettings=
message_error_tempDirectory=
message_error_cacheDirectory=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add actual text somewhere 🙄 double check if there is an error label w.r.t. to download directory.

@skaldarnar skaldarnar merged commit ffd1120 into develop Nov 3, 2019
@skaldarnar skaldarnar deleted the update/package-manager branch November 3, 2019 21:04
keturn added a commit to keturn/TerasologyLauncher that referenced this pull request Apr 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve Package Manager architecture
4 participants