private async function generateAsync()

in src/__Private/codegen/CodegenRelations.hack [36:126]


  private async function generateAsync(): Awaitable<void> {
    print("Generating file list to infer relationships...\n");
    $files = $this->getFileList();
    print("Infering relationships, this can take a long time...\n");
    $done = new Ref(0);
    $start = \microtime(true);

    $relationships = new Ref(dict[]);
    $queue = new Async\Semaphore(
      /* limit = */ 32,
      async $file ==> {
        try {
          $links = await $this->getRelationsInFileAsync($file);
          $new = dict[];
          foreach ($links as $key => $children) {
            $relationships->v[$key] ??= keyset[];
            $new_children = Keyset\diff($children, $relationships->v[$key]);
            if ($new_children) {
              $new[$key] = $children;
            }
          }
          if ($new) {
            await execute_async('hhvm', '-l', $file);
            foreach ($new as $key => $children) {
              $relationships->v[$key] = Keyset\union(
                $relationships->v[$key],
                $children,
              );
            }
          }
        } catch (\Throwable $_) {
          // HHVM and Hack tests intentionally include lots of invalid
          // files
        } finally {
          $done->v++;
        }

      },
    );
    concurrent {
      await Dict\map_async(
        $files,
        async $file ==> await $queue->waitForAsync($file),
      );
      await async {
        $total = C\count($files);
        while ($done->v < $total) {
          /* HHAST_IGNORE_ERROR[DontAwaitInALoop] */
          await \HH\Asio\usleep(1000 * 1000);
          if ($done->v === 0) {
            continue;
          }
          $ratio = ((float)$done->v) / $total;
          $now = \microtime(true);
          $elapsed = $now - $start;
          $rate = $done->v / $elapsed;
          $end = $start + ($total / $rate);
          \fprintf(
            \STDERR,
            "%d%%\t(%d / %d)\tExpected finish in %ds at %s\n",
            (int)($ratio * 100),
            $done->v,
            $total,
            (int)($end - $now),
            \strftime('%H:%M:%S', (int)$end),
          );
        }
      };
    }

    $cg = $this->getCodegenFactory();

    $cg->codegenFile($this->getOutputDirectory().'/inferred_relationships.hack')
      ->setFileType(CodegenFileType::DOT_HACK)
      ->setNamespace('Facebook\\HHAST\\__Private')
      ->addConstant(
        $cg->codegenConstant('INFERRED_RELATIONSHIPS')
          ->setType('dict<string, keyset<string>>')
          ->setValue(
            $relationships->v
              |> Dict\sort_by_key($$)
              |> Dict\map($$, $children ==> Keyset\sort($children)),
            HackBuilderValues::dict(
              HackBuilderKeys::export(),
              HackBuilderValues::keyset(HackBuilderValues::export()),
            ),
          ),
      )
      ->save();
    print("... done!\n");
  }