// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart' as p;

// This script verifies that the release binaries only export the expected
// symbols.
//
// Android binaries (libflutter.so) should only export one symbol "JNI_OnLoad"
// of type "T".
//
// iOS binaries (Flutter.framework/Flutter) should only export Objective-C
// Symbols from the Flutter namespace. These are either of type
// "(__DATA,__common)" or "(__DATA,__objc_data)".

/// Takes the path to the out directory as the first argument, and the path to
/// the buildtools directory as the second argument.
///
/// If the second argument is not specified, for backwards compatibility, it is
/// assumed that it is ../buildtools relative to the first parameter (the out
/// directory).
void main(List<String> arguments) {
  if (arguments.isEmpty || arguments.length > 2) {
    print('usage: dart verify_exported.dart OUT_DIR [BUILDTOOLS]');
    exit(1);
  }
  String outPath = arguments.first;
  if (p.isRelative(outPath)) {
    /// If path is relative then create a full path starting from the engine checkout
    /// repository.
    if (!Platform.environment.containsKey('ENGINE_CHECKOUT_PATH')) {
      print('ENGINE_CHECKOUT_PATH env variable is mandatory when using relative destination path');
      exit(1);
    }
    final String engineCheckoutPath = Platform.environment['ENGINE_CHECKOUT_PATH']!;
    outPath = p.join(engineCheckoutPath, outPath);
  }
  final String buildToolsPath = arguments.length == 1
      ? p.join(p.dirname(outPath), 'flutter', 'buildtools')
      : arguments[1];

  String platform;
  if (Platform.isLinux) {
    platform = 'linux-x64';
  } else if (Platform.isMacOS) {
    platform = 'mac-x64';
  } else {
    throw UnimplementedError('Script only support running on Linux or MacOS.');
  }
  final String nmPath = p.join(buildToolsPath, platform, 'clang', 'bin', 'llvm-nm');
  if (!Directory(outPath).existsSync()) {
    print('error: build out directory not found: $outPath');
    exit(1);
  }

  final Iterable<String> releaseBuilds = Directory(outPath).listSync()
      .whereType<Directory>()
      .map<String>((FileSystemEntity dir) => p.basename(dir.path))
      .where((String s) => s.contains('_release'));

  final Iterable<String> iosReleaseBuilds = releaseBuilds
      .where((String s) => s.startsWith('ios_'));
  final Iterable<String> androidReleaseBuilds = releaseBuilds
      .where((String s) => s.startsWith('android_'));
  final Iterable<String> hostReleaseBuilds = releaseBuilds
      .where((String s) => s.startsWith('host_'));

  int failures = 0;
  failures += _checkIos(outPath, nmPath, iosReleaseBuilds);
  failures += _checkAndroid(outPath, nmPath, androidReleaseBuilds);
  if (Platform.isLinux) {
    failures += _checkLinux(outPath, nmPath, hostReleaseBuilds);
  }
  print('Failing checks: $failures');
  exit(failures);
}

int _checkIos(String outPath, String nmPath, Iterable<String> builds) {
  int failures = 0;
  for (final String build in builds) {
    final String libFlutter = p.join(outPath, build, 'Flutter.framework', 'Flutter');
    if (!File(libFlutter).existsSync()) {
      print('SKIPPING: $libFlutter does not exist.');
      continue;
    }
    final ProcessResult nmResult = Process.runSync(nmPath, <String>['-gUm', libFlutter]);
    if (nmResult.exitCode != 0) {
      print('ERROR: failed to execute "nm -gUm $libFlutter":\n${nmResult.stderr}');
      failures++;
      continue;
    }
    final Iterable<NmEntry> unexpectedEntries = NmEntry.parse(nmResult.stdout as String).where((NmEntry entry) {
      final bool cSymbol = (entry.type == '(__DATA,__common)' || entry.type == '(__DATA,__const)')
          && entry.name.startsWith('_Flutter');
      final bool cInternalSymbol = entry.type == '(__TEXT,__text)' && entry.name.startsWith('_InternalFlutter');
      final bool objcSymbol = entry.type == '(__DATA,__objc_data)'
          && (entry.name.startsWith(r'_OBJC_METACLASS_$_Flutter') || entry.name.startsWith(r'_OBJC_CLASS_$_Flutter'));
      return !(cSymbol || cInternalSymbol || objcSymbol);
    });
    if (unexpectedEntries.isNotEmpty) {
      print('ERROR: $libFlutter exports unexpected symbols:');
      print(unexpectedEntries.fold<String>('', (String previous, NmEntry entry) {
        return '${previous == '' ? '' : '$previous\n'}     ${entry.type} ${entry.name}';
      }));
      failures++;
    } else {
      print('OK: $libFlutter');
    }
  }
  return failures;
}

int _checkAndroid(String outPath, String nmPath, Iterable<String> builds) {
  int failures = 0;
  for (final String build in builds) {
    final String libFlutter = p.join(outPath, build, 'libflutter.so');
    if (!File(libFlutter).existsSync()) {
      print('SKIPPING: $libFlutter does not exist.');
      continue;
    }
    final ProcessResult nmResult = Process.runSync(nmPath, <String>['-gU', libFlutter]);
    if (nmResult.exitCode != 0) {
      print('ERROR: failed to execute "nm -gU $libFlutter":\n${nmResult.stderr}');
      failures++;
      continue;
    }
    final Iterable<NmEntry> entries = NmEntry.parse(nmResult.stdout as String);
    final Map<String, String> entryMap = <String, String>{
      for (final NmEntry entry in entries)
        entry.name: entry.type,
    };
    final Map<String, String> expectedSymbols = <String, String>{
      'JNI_OnLoad': 'T',
      '_binary_icudtl_dat_size': 'R',
      '_binary_icudtl_dat_start': 'R',
    };
    final Map<String, String> badSymbols = <String, String>{};
    for (final String key in entryMap.keys) {
      if (entryMap[key] != expectedSymbols[key]) {
        badSymbols[key] = entryMap[key]!;
      }
    }
    if (badSymbols.isNotEmpty) {
      print('ERROR: $libFlutter exports the wrong symbols');
      print(' Expected $expectedSymbols');
      print(' Library has $entryMap.');
      failures++;
    } else {
      print('OK: $libFlutter');
    }
  }
  return failures;
}

int _checkLinux(String outPath, String nmPath, Iterable<String> builds) {
  int failures = 0;
  for (final String build in builds) {
    final String libFlutter = p.join(outPath, build, 'libflutter_engine.so');
    if (!File(libFlutter).existsSync()) {
      print('SKIPPING: $libFlutter does not exist.');
      continue;
    }
    final ProcessResult nmResult = Process.runSync(nmPath, <String>['-gUD', libFlutter]);
    if (nmResult.exitCode != 0) {
      print('ERROR: failed to execute "nm -gUD $libFlutter":\n${nmResult.stderr}');
      failures++;
      continue;
    }
    final List<NmEntry> entries = NmEntry.parse(nmResult.stdout as String).toList();
    for (final NmEntry entry in entries) {
      if (entry.type != 'T' && entry.type != 'R') {
        print('ERROR: $libFlutter exports an unexpected symbol type: ($entry)');
        print(' Library has $entries.');
        failures++;
        break;
      }
      if (!(entry.name.startsWith('Flutter')
            || entry.name.startsWith('__Flutter')
            || entry.name.startsWith('kFlutter')
            || entry.name.startsWith('InternalFlutter')
            || entry.name.startsWith('kInternalFlutter'))) {
        print('ERROR: $libFlutter exports an unexpected symbol name: ($entry)');
        print(' Library has $entries.');
        failures++;
        break;
      }
    }
  }
  return failures;
}

class NmEntry {
  NmEntry._(this.type, this.name);

  final String type;
  final String name;

  static Iterable<NmEntry> parse(String stdout) {
    return LineSplitter.split(stdout).map((String line) {
      final List<String> parts = line.split(' ');
      return NmEntry._(parts[1], parts.last);
    });
  }

  @override
  String toString() => '$name: $type';
}
