class PipWrapper {

  public Set<PipInstalledPackage> getListPackages()
      throws ProcessWrapperException, IOException, InterruptedException {
    final StopWatch sw = new StopWatch("pip list").start();

    // Try legacy format
    ProcessWrapper pw =
        new ProcessWrapper()
            .setCommand(this.pathToPip, "list", "--format", "legacy")
            .setPath(logDir);
    Thread t = new Thread(pw, "pip");
    t.start();
    t.join();

    Set<PipInstalledPackage> packages = null;
    if (pw.terminatedWithSuccess()) {
      packages = this.parsePipListOutput(pw.getOutFile());
    }
    // Try JSON format
    else {
      log.info("Legacy format did not work, trying JSON format...");
      pw =
          new ProcessWrapper()
              .setCommand(this.pathToPip, "list", "--format", "json")
              .setPath(logDir);
      t = new Thread(pw, "pip");
      t.start();
      t.join();
      if (pw.terminatedWithSuccess()) packages = this.deserializePipListOutput(pw.getOutFile());
    }

    // Collect package details
    if (packages != null) {
      log.info("Found [" + packages.size() + "] pip packages:");
      for (PipInstalledPackage pack : packages) log.info("    " + pack);

      // Call pip show in separate threads
      final ExecutorService pool =
          Executors.newFixedThreadPool(ThreadUtil.getNoThreads(2)); // newSingleThreadExecutor();
      final Set<Future<PipInstalledPackage>> futures = new HashSet<Future<PipInstalledPackage>>();
      for (PipInstalledPackage pack : packages) {
        futures.add(pool.submit(new PipShow(pack)));
      }
      pool.shutdown();
      try {
        while (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
          int done = 0;
          for (Future<PipInstalledPackage> f : futures) {
            if (f.isDone()) done++;
          }
          sw.lap("[" + done + "/" + futures.size() + "] pip jobs are done");
        }
      } catch (InterruptedException e) {
        PipWrapper.log.error("Interrupt exception");
      }
    } else {
      log.warn("No pip packages found with pip list");
    }

    sw.stop();
    return packages;
  }

  public  PipWrapper();
  public  PipWrapper(Path _path_to_pip, Path _log_dir);

}