java_and_objc_doc.dart 3.58 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:io';
6
import 'dart:math';
7 8 9

import 'package:archive/archive.dart';
import 'package:http/http.dart' as http;
10
import 'package:path/path.dart' as path;
11 12 13 14 15

const String kDocRoot = 'dev/docs/doc';

/// This script downloads an archive of Javadoc and objc doc for the engine from
/// the artifact store and extracts them to the location used for Dartdoc.
16
Future<void> main(List<String> args) async {
17
  final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim();
18

19
  final String javadocUrl = 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineVersion/android-javadoc.zip';
20 21
  generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html');

22
  final String objcdocUrl = 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip';
23
  generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html');
24 25
}

26 27 28
/// Fetches the zip archive at the specified url.
///
/// Returns null if the archive fails to download after [maxTries] attempts.
29 30
Future<Archive?> fetchArchive(String url, int maxTries) async {
  List<int>? responseBytes;
31
  for (int i = 0; i < maxTries; i++) {
32
    final http.Response response = await http.get(Uri.parse(url));
33 34 35 36 37 38 39
    if (response.statusCode == 200) {
      responseBytes = response.bodyBytes;
      break;
    }
    stderr.writeln('Failed attempt ${i+1} to fetch $url.');

    // On failure print a short snipped from the body in case it's helpful.
40
    final int bodyLength = min(1024, response.body.length);
41
    stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}');
42 43 44 45
    sleep(const Duration(seconds: 1));
  }
  return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes);
}
46

47 48
Future<void> generateDocs(String url, String docName, String checkFile) async {
  const int maxTries = 5;
49
  final Archive? archive = await fetchArchive(url, maxTries);
50 51 52 53
  if (archive == null) {
    stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.');
    exit(1);
  }
54

55
  final Directory output = Directory('$kDocRoot/$docName');
56
  print('Extracting $docName to ${output.path}');
57 58
  output.createSync(recursive: true);

59
  for (final ArchiveFile af in archive) {
Dan Field's avatar
Dan Field committed
60
    if (!af.name.endsWith('/')) {
61
      final File file = File('${output.path}/${af.name}');
62
      file.createSync(recursive: true);
63
      file.writeAsBytesSync(af.content as List<int>);
64 65 66
    }
  }

67 68 69 70 71 72
  /// If object then copy files to old location if the archive is using the new location.
  final bool exists = Directory('$kDocRoot/$docName/objectc_docs').existsSync();
  if (exists) {
    copyFolder(Directory('$kDocRoot/$docName/objectc_docs'), Directory('$kDocRoot/$docName/'));
  }

73
  final File testFile = File('${output.path}/$checkFile');
74 75 76 77 78 79
  if (!testFile.existsSync()) {
    print('Expected file ${testFile.path} not found');
    exit(1);
  }
  print('$docName ready to go!');
}
80 81 82 83 84 85 86 87 88 89 90 91 92 93

/// Copies the files in a directory recursively to a new location.
void copyFolder(Directory source, Directory destination) {
  source.listSync()
  .forEach((FileSystemEntity entity) {
    if (entity is Directory) {
      final Directory newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path)));
      newDirectory.createSync();
      copyFolder(entity.absolute, newDirectory);
    } else if (entity is File) {
      entity.copySync(path.join(destination.path, path.basename(entity.path)));
    }
  });
}