<commit_before>// Copyright 2017 The Chromium 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 'package:pub_semver/pub_semver.dart';

import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process_manager.dart';
import '../globals.dart';
import '../ios/plist_utils.dart';

AndroidStudio get androidStudio =>
    context.putIfAbsent(AndroidStudio, AndroidStudio.latestValid);

// Android Studio layout:

// Linux/Windows:
// $HOME/.AndroidStudioX.Y/system/.home

// macOS:
// /Applications/Android Studio.app/Contents/
// $HOME/Applications/Android Studio.app/Contents/

// $STUDIO_HOME/gradle/gradle-X.Y.Z/bin/gradle

final Version minGradleVersion = new Version(2, 14, 1);

/// Locate Gradle.
String get gradleExecutable {
  // See if the user has explicitly configured gradle-dir.
  String gradleDir = config.getValue('gradle-dir');
  if (gradleDir != null) {
    if (fs.isFileSync(gradleDir))
      return gradleDir;
    return fs.path.join(gradleDir, 'bin', 'gradle');
  }
  return androidStudio?.gradleExecutable ?? os.which('gradle')?.path;
}

class AndroidStudio implements Comparable<AndroidStudio> {
  AndroidStudio(this.directory, {this.version = '0.0', this.configured}) {
    _init();
  }

  final String directory;
  final String version;
  final String configured;

  String _gradlePath;
  bool _isValid = false;
  List<String> _validationMessages = <String>[];

  factory AndroidStudio.fromMacOSBundle(String bundlePath) {
    String studioPath = fs.path.join(bundlePath, 'Contents');
    String plistFile = fs.path.join(studioPath, 'Info.plist');
    String version =
        getValueFromFile(plistFile, kCFBundleShortVersionStringKey);
    return new AndroidStudio(studioPath, version: version);
  }

  factory AndroidStudio.fromHomeDot(Directory homeDotDir) {
    String version = homeDotDir.basename.substring('.AndroidStudio'.length);
    String installPath;
    try {
      installPath = fs
          .file(fs.path.join(homeDotDir.path, 'system', '.home'))
          .readAsStringSync();
    } catch (e) {
      // ignored
    }
    if (installPath != null && fs.isDirectorySync(installPath)) {
      return new AndroidStudio(installPath, version: version);
    }
    return null;
  }

  String get gradlePath => _gradlePath;

  String get gradleExecutable => fs.path
      .join(_gradlePath, 'bin', platform.isWindows ? 'gradle.bat' : 'gradle');

  bool get isValid => _isValid;

  List<String> get validationMessages => _validationMessages;

  @override
  int compareTo(AndroidStudio other) {
    int result = version.compareTo(other.version);
    if (result == 0)
      return directory.compareTo(other.directory);
    return result;
  }

  /// Locates the newest, valid version of Android Studio.
  static AndroidStudio latestValid() {
    String configuredStudio = config.getValue('android-studio-dir');
    if (configuredStudio != null) {
      String configuredStudioPath = configuredStudio;
      if (os.isMacOS && !configuredStudioPath.endsWith('Contents'))
        configuredStudioPath = fs.path.join(configuredStudioPath, 'Contents');
      return new AndroidStudio(configuredStudioPath,
          configured: configuredStudio);
    }

    // Find all available Studio installations.
    List<AndroidStudio> studios = allInstalled();
    if (studios.isEmpty) {
      return null;
    }
    studios.sort();
    return studios.lastWhere((AndroidStudio s) => s.isValid,
        orElse: () => null);
  }

  static List<AndroidStudio> allInstalled() =>
      platform.isMacOS ? _allMacOS() : _allLinuxOrWindows();

  static List<AndroidStudio> _allMacOS() {
    List<FileSystemEntity> candidatePaths = <FileSystemEntity>[];

    void _checkForStudio(String path) {
      if (!fs.isDirectorySync(path))
        return;
      List<Directory> directories = fs
          .directory(path)
          .listSync()
          .where((FileSystemEntity e) => e is Directory);
      for (Directory directory in directories) {
        if (directory.basename == 'Android Studio.app') {
          candidatePaths.add(directory);
        } else if (!directory.path.endsWith('.app')) {
          _checkForStudio(directory.path);
        }
      }
    }

    _checkForStudio('/Applications');
    _checkForStudio(fs.path.join(homeDirPath, 'Applications'));

    String configuredStudioDir = config.getValue('android-studio-dir');
    if (configuredStudioDir != null) {
      FileSystemEntity configuredStudio = fs.file(configuredStudioDir);
      if (configuredStudio.basename == 'Contents') {
        configuredStudio = configuredStudio.parent;
      }
      if (!candidatePaths
          .any((FileSystemEntity e) => e.path == configuredStudio.path)) {
        candidatePaths.add(configuredStudio);
      }
    }
<commit_msg>One more fix for finding Android Studio on macOS. (#8288)<commit_after>// Copyright 2017 The Chromium 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 'package:pub_semver/pub_semver.dart';

import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process_manager.dart';
import '../globals.dart';
import '../ios/plist_utils.dart';

AndroidStudio get androidStudio =>
    context.putIfAbsent(AndroidStudio, AndroidStudio.latestValid);

// Android Studio layout:

// Linux/Windows:
// $HOME/.AndroidStudioX.Y/system/.home

// macOS:
// /Applications/Android Studio.app/Contents/
// $HOME/Applications/Android Studio.app/Contents/

// $STUDIO_HOME/gradle/gradle-X.Y.Z/bin/gradle

final Version minGradleVersion = new Version(2, 14, 1);

/// Locate Gradle.
String get gradleExecutable {
  // See if the user has explicitly configured gradle-dir.
  String gradleDir = config.getValue('gradle-dir');
  if (gradleDir != null) {
    if (fs.isFileSync(gradleDir))
      return gradleDir;
    return fs.path.join(gradleDir, 'bin', 'gradle');
  }
  return androidStudio?.gradleExecutable ?? os.which('gradle')?.path;
}

class AndroidStudio implements Comparable<AndroidStudio> {
  AndroidStudio(this.directory, {this.version = '0.0', this.configured}) {
    _init();
  }

  final String directory;
  final String version;
  final String configured;

  String _gradlePath;
  bool _isValid = false;
  List<String> _validationMessages = <String>[];

  factory AndroidStudio.fromMacOSBundle(String bundlePath) {
    String studioPath = fs.path.join(bundlePath, 'Contents');
    String plistFile = fs.path.join(studioPath, 'Info.plist');
    String version =
        getValueFromFile(plistFile, kCFBundleShortVersionStringKey);
    return new AndroidStudio(studioPath, version: version);
  }

  factory AndroidStudio.fromHomeDot(Directory homeDotDir) {
    String version = homeDotDir.basename.substring('.AndroidStudio'.length);
    String installPath;
    try {
      installPath = fs
          .file(fs.path.join(homeDotDir.path, 'system', '.home'))
          .readAsStringSync();
    } catch (e) {
      // ignored
    }
    if (installPath != null && fs.isDirectorySync(installPath)) {
      return new AndroidStudio(installPath, version: version);
    }
    return null;
  }

  String get gradlePath => _gradlePath;

  String get gradleExecutable => fs.path
      .join(_gradlePath, 'bin', platform.isWindows ? 'gradle.bat' : 'gradle');

  bool get isValid => _isValid;

  List<String> get validationMessages => _validationMessages;

  @override
  int compareTo(AndroidStudio other) {
    int result = version.compareTo(other.version);
    if (result == 0)
      return directory.compareTo(other.directory);
    return result;
  }

  /// Locates the newest, valid version of Android Studio.
  static AndroidStudio latestValid() {
    String configuredStudio = config.getValue('android-studio-dir');
    if (configuredStudio != null) {
      String configuredStudioPath = configuredStudio;
      if (os.isMacOS && !configuredStudioPath.endsWith('Contents'))
        configuredStudioPath = fs.path.join(configuredStudioPath, 'Contents');
      return new AndroidStudio(configuredStudioPath,
          configured: configuredStudio);
    }

    // Find all available Studio installations.
    List<AndroidStudio> studios = allInstalled();
    if (studios.isEmpty) {
      return null;
    }
    studios.sort();
    return studios.lastWhere((AndroidStudio s) => s.isValid,
        orElse: () => null);
  }

  static List<AndroidStudio> allInstalled() =>
      platform.isMacOS ? _allMacOS() : _allLinuxOrWindows();

  static List<AndroidStudio> _allMacOS() {
    List<FileSystemEntity> candidatePaths = <FileSystemEntity>[];

    void _checkForStudio(String path) {
      if (!fs.isDirectorySync(path))
        return;
      Iterable<Directory> directories = fs
          .directory(path)
          .listSync()
          .where((FileSystemEntity e) => e is Directory);
      for (Directory directory in directories) {
        if (directory.basename == 'Android Studio.app') {
          candidatePaths.add(directory);
        } else if (!directory.path.endsWith('.app')) {
          _checkForStudio(directory.path);
        }
      }
    }

    _checkForStudio('/Applications');
    _checkForStudio(fs.path.join(homeDirPath, 'Applications'));

    String configuredStudioDir = config.getValue('android-studio-dir');
    if (configuredStudioDir != null) {
      FileSystemEntity configuredStudio = fs.file(configuredStudioDir);
      if (configuredStudio.basename == 'Contents') {
        configuredStudio = configuredStudio.parent;
      }
      if (!candidatePaths
          .any((FileSystemEntity e) => e.path == configuredStudio.path)) {
        candidatePaths.add(configuredStudio);
      }
    }

{'fraction_non_alphanumeric': 0.12444623439387838, 'fraction_numerical': 0.002617801047120419, 'mean_word_length': 3.424498886414254, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3399666', 'n_tokens_mistral': 3029, 'n_tokens_neox': 2842, 'n_words': 659}