content: import java.io.File;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.util.Arrays;
  import java.util.List;
  
  import com.adacore.libadalang.Libadalang;
  
  public class ProjectManager {
  
      /** The directory which contains the projects */
      private static String projectPath;
  
      /**
       * Display the section header with the given name
       *
       * @param name The name of the section
       */
      private static void header(String name) {
          System.out.println("--- " + name + " ---");
      }
  
      /**
       * Display the footer of a section
       *
       * @param name The name of the section
       */
      private static void footer(String name) {
          System.out.println("----" + "-".repeat(name.length()) + "----\n");
      }
  
      /**
       * Util function to display all information about a project manager.
       */
      private static void projectInfo(
          Libadalang.ProjectManager project,
          String subproject
      ) {
          // Display the project manager diagnostics if any
          List<String> diagnostics = project.getDiagnostics();
          if (diagnostics.size() > 0) {
              System.out.println("Error during project opening:");
              System.out.println("  " + diagnostics);
          }
  
          String[] files = project.getFiles(
              Libadalang.SourceFileMode.ROOT_PROJECT,
              subproject == null ? null : new String[] {subproject}
          );
  
          // Create an analysis context with the project unit provider
          Libadalang.UnitProvider unitProvider =
              project.getProvider(subproject);
  
          // Create an event handler
          Libadalang.EventHandler eh = Libadalang.EventHandler.create(
              (ctx, name, from, found, notFoundIsError) -> {
                  if (!found && notFoundIsError) {
                      System.out.println(
                          "Cannot find file " + new File(name).getName()
                      );
                  }
              },
              null);
  
          try(
             Libadalang.AnalysisContext context =
                 Libadalang.AnalysisContext.create(
                     null,
                     null,
                     unitProvider,
                     eh,
                     true,
                     8
                 )
          ) {
              for(String file : files) {
                  Libadalang.AnalysisUnit unit =
                      context.getUnitFromFile(file);
                  System.out.println("File " + unit.getFileName(false));
                  System.out.println("  root = " + unit.getRoot());
                  System.out.println(
                      "  deps = " +
                      Arrays.toString(
                          ((Libadalang.CompilationUnit) unit.getRoot())
                              .pUnitDependencies()
                      )
                  );
              }
          }
      }
  
      /** Simply open the given GPR file and display its source files. */
      private static void openProject(String gprFile) {
          openProject(
              gprFile,
              null
          );
      }
  
      /**
       * Open the given GPR file with a subproject to use, then display its
       * source files.
       */
      private static void openProject(
          String gprFile,
          String subproject
      ) {
          openProject(
              gprFile,
              subproject,
              null,
              true
          );
      }
  
      /**
       * Open a GPR project and list its source files.
       *
       * @param gprFile The gpr file
       * @param subproject The subproject to use. If null, use the root project
       *     in the given project path
       * @param scenarioVariables Scenario variables to apply during project
       *     opening
       * @param lookInProjectPath If the function should look for the GPR file
       */
      private static void openProject(
          String gprFile,
          String subproject,
          String[] scenarioVariables,
          boolean lookInProjectPath
      ) {
          openProject(
              gprFile,
              subproject,
              null,
              scenarioVariables,
              lookInProjectPath
          );
      }
  
      /**
       * Open a gpr project and list its source files.
       *
       * @param gprFile The gpr file
       * @param subproject The subproject to use. If null, use the root project
       *     in the given project path
       * @param configFile A configuration file to open the project with
       * @param scenarioVariables Scenario variables to apply during project
       *     opening
       * @param lookInProjectPath If the function should look for the GPR file
       */
      private static void openProject(
          String gprFile,
          String subproject,
          String configFile,
          String[] scenarioVariables,
          boolean lookInProjectPath
      ) {
          openProject(
              gprFile,
              subproject,
              configFile,
              scenarioVariables,
              lookInProjectPath,
              false
          );
      }
  
      private static void openProject(
          String gprFile,
          String subproject,
          String configFile,
          String[] scenarioVariables,
          boolean lookInProjectPath,
          boolean adaOnly
      ) {
          String headerMsg = "Open " + Paths.get(gprFile).getFileName();
          if (subproject != null) {
              headerMsg += " (" + subproject + ")";
          }
          if (configFile != null) {
              headerMsg += " with config " + configFile;
          }
          if (adaOnly) {
              headerMsg += " | Ada only";
          }
          header(headerMsg);
  
          // Resolve the project file if needed
          if(lookInProjectPath) {
              gprFile = Paths.get(projectPath, gprFile).toString();
              configFile = configFile == null ?
                  null :
                  Paths.get(projectPath, configFile).toString();
          }
  
          try (
              Libadalang.ProjectOptions options =
                  new Libadalang.ProjectOptions();
          ) {
              options.addSwitch(Libadalang.ProjectOption.P, gprFile);
              if (configFile != null) {
                  options.addSwitch(Libadalang.ProjectOption.CONFIG, configFile);
              }
              if (scenarioVariables != null) {
                  for (int i = 0; i < scenarioVariables.length; ++i) {
                      options.addSwitch(
                          Libadalang.ProjectOption.X,
                          scenarioVariables[i]
                      );
                  }
              }
  
              try(
                  Libadalang.ProjectManager project =
                      new Libadalang.ProjectManager(options, adaOnly)
              ) {
                  projectInfo(project, subproject);
              } catch (Libadalang.ProjectManagerException e) {
                  System.out.println(e.getMessage());
              } finally {
                  footer(headerMsg);
              }
          }
      }
  
      /**
       * Test opening a valid project.
       */
      private static void testValid() {
          openProject("p1.gpr");
          openProject(
              "p2.gpr",
              null,
              new String[] {
                  "SRC_DIR=src2_1",
                  "USELESS=useless"
              },
              true
          );
          openProject(
              "p2.gpr",
              null,
              new String[] {"SRC_DIR=src2_2"},
              true
          );
      }
  
      /**
       * Test loading a project with a null GPROptions argument.
       */
      private static void testNullOptions() {
          final String headerMsg = "Null GPROptions argument";
          header (headerMsg);
          try(
              Libadalang.ProjectManager project =
                  new Libadalang.ProjectManager(null, false);
          ) {
              System.out.println("... unexpected success...");
          } catch (Libadalang.ProjectManagerException e) {
              System.out.println("ProjectManagerException:");
              System.out.println(e.getMessage());
          } finally {
              footer(headerMsg);
          }
      }
  
      /**
       * Test opening an invalid project.
       */
      private static void testInvalid() {
          openProject("invalid.gpr");
      }
  
      /**
       * Test opening an inexistant project.
       */
      private static void testInexistant() {
          openProject("idonotexist.gpr", null, null, false);
      }
  
      /**
       * Test opening an aggregate project.
       */
      private static void testAggregate() {
          openProject("agg.gpr", "nosuchsubproject");
          openProject("agg.gpr", "p1");
          openProject("agg.gpr", "p2");
      }
  
      private static void testNoSuchTarget() {
          openProject("nosuchtarget.gpr");
      }
  
      /**
       * Test the opening of an implicit project.
       */
      private static void testImplicit() {
          String headerMsg = "Open implicit project";
          header(headerMsg);
  
          Libadalang.ProjectOptions options = new Libadalang.ProjectOptions();
          options.addSwitch(Libadalang.ProjectOption.NO_PROJECT);
          try (
              Libadalang.ProjectManager project =
                  new Libadalang.ProjectManager(options, false)
          ) {
              projectInfo(project, null);
          } catch (Libadalang.ProjectManagerException e) {
              System.out.println(e.getMessage());
          } finally {
              footer(headerMsg);
          }
      }
  
      private static void testConfigFile() {
          openProject(
              "p1.gpr",
              null,
              "other_naming.cgpr",
              null,
              true
          );
      }
  
      private static void testValidConfigFile() {
          openProject("for_cgpr.gpr");
          openProject(
              Paths.get(projectPath, "for_cgpr.gpr").toString(),
              null,
              "custom.cgpr",
              null,
              false
          );
      }
  
      private static void testEmptyConfigFile() {
          openProject(
              "p1.gpr",
              null,
              "empty.cgpr",
              null,
              true
          );
      }
  
      private static void testInexistantConfigFile() {
          openProject(
              Paths.get(projectPath, "p1.gpr").toString(),
              null,
              "idonotexist.cgpr",
              null,
              false
          );
      }
  
      private static void testAdaOnly() {
          openProject(
              "ada_only.gpr",
              null,
              null,
              null,
              true,
              true
          );
          openProject(
              "ada_only.gpr",
              null,
              null,
              null,
              true,
              false
          );
      }
  
      /**
       * Run the tests
       */
      public static void main(String[] args) {
          projectPath = args[0];
          testValid();
          testNullOptions();
          testInvalid();
          testInexistant();
          testAggregate();
          testNoSuchTarget();
          testImplicit();
          testConfigFile();
          testValidConfigFile();
          testEmptyConfigFile();
          testInexistantConfigFile();
          testAdaOnly();
      }
  }
  