Class DependencyManager

java.lang.Object
org.ek9lang.cli.DependencyManager

final class DependencyManager extends Object
Designed to deal with managing dependencies of ek9 modules. So when an ek9 module is defined and packaged it can reference dependencies and development dependencies. These are basically a mix of both the module name and a version number. Note that the module scope package IS public interface to your package, if you want internal, implementations constructs put them in a module under the module you are packaging. For example if publishing/packaging ek9open.google.tools.networking, and you want to have internal stuff that can only be used inside the package then use: ek9open.google.tools.networking.internal or ek9open.google.tools.networking.utils etc. Full vector could be 'ek9open.google.tools.networking.utils-1.0.8-5' module '-' MAJOR '.' MINOR '.' PATCH '-' BUILD For feature branch builds it might be 'ek9open.google.tools.networking.utils-1.0.8-VSTS9889-5' module '-' MAJOR '.' MINOR '.' PATCH ('-' FEATURE)? '-' BUILD The actual artefact would have a suffix of '.zip' So what's the big issue here, well we need to: 1. Prohibit and detect circular dependencies. 2. Remove dependencies that the developer does not want to include that other dependencies might pull in. 3. Ensure only a single version (highest based on version numbering) is included. 4. For semanticVersioning - fail build if major version gets pulled up when other dependencies need lower version. For semantic versioning major > minor > patch > build and patch without feature is higher. Features are ordered by alpha. i.e. Alpha > Beta for example. This is done with a directed graph with back pointers back up the graph tree. The main Nodes in the graph hold both the moduleName and the Version separately and have a flag to denote rejection. They also hold a list of other Nodes that they depend on. Once you have checked for circular dependencies (and there are none) You can then use or reject exclude modules. Then use this method so that modules that are the same but different version numbers can be rationalised. This means finding the module of the same name but the highest version (that has not already been rejected). Only keep the highest none rejected version, mark others as rejected. BUT NOTE this sometimes means additional dependencies get included because we might have rejected a module that had a number of dependencies that only that version of the module used! At the end it is possible the developer excluded a set of dependencies that were needed. The compiler will let the developer know because there will be missing symbols.
  • Constructor Details

  • Method Details

    • rationalise

      void rationalise()
      Mark modules as rejected if there is a higher version of the same module (that is not marked as rejected).
    • optimise

      boolean optimise(int numberOfOptimiseCalls)
      Marks dependencies that fall along a reject path as rejected. Can and probably should be called in a loop until returns false. Because you might process nodes in an order where a lower level tree node has a viable path back to parent and so is not marked as rejected. But then a little later in the processing a critical node in the path is marked as rejected. Now the lower level one does not have path back. So call in a loop until fully optimised.
      Returns:
      true is optimisation took place, false if there was nothing to optimise.
    • reportStrictSemanticVersionBreaches

      List<DependencyNode> reportStrictSemanticVersionBreaches()
      Any situation where the top selected dependency has one or more, lower version numbers where the major version is less that that selected. Basically this means you cannot continue with this set of dependencies - it just won't work at all for you. Unlike Java, we do actually get the packages and recompile them, so public interfaces in packages must match.
      Returns:
      The list of offending nodes.
    • reportRejectedDependencies

      List<DependencyNode> reportRejectedDependencies()
      Provide a list of all rejected dependencies.
      Returns:
      The list.
    • reportAcceptedDependencies

      List<DependencyNode> reportAcceptedDependencies()
      Provide a list of all accepted dependencies.
      Returns:
      The list.
    • reject

      void reject(String moduleName, String whenDependencyOf)
      Reject a moduleName dependency if is has been pulled in when is it a dependency of another module.
    • listAllModuleNames

      List<String> listAllModuleNames()
      Traverse the tree graph to find all the distinct module names in use ignoring the version numbers.
      Returns:
      The list of unique module names.
    • findByModuleName

      List<DependencyNode> findByModuleName(String moduleName)
      Search for a particular moduleName, can return multiple matches if there are multiple versions of the same dependency. The highest version number is returned first.
      Parameters:
      moduleName - The module name to search for.
      Returns:
      The list of modules that match (i.e. same module name but maybe multiple versions).
    • reportAllDependencies

      List<String> reportAllDependencies()
      Reports all the dependencies there are from root. If root is not set then this is an empty list.
      Returns:
      The list of all the dependencies.
    • reportCircularDependencies

      List<String> reportCircularDependencies(boolean includeVersion)
      Check if there are any circular references and report back up on the path the dependency was found in.
      Returns:
      One or more circular paths in the graph/tree.
    • reportCircularDependencies

      List<String> reportCircularDependencies()