xcode.dart 3.92 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 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 'dart:async';

7
import '../base/common.dart';
8 9 10
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
11
import '../base/platform.dart';
12 13 14 15 16 17 18 19 20
import '../base/process.dart';
import '../ios/xcodeproj.dart';

const int kXcodeRequiredVersionMajor = 9;
const int kXcodeRequiredVersionMinor = 0;

Xcode get xcode => context.get<Xcode>();

class Xcode {
21
  bool get isInstalledAndMeetsVersionCheck => platform.isMacOS && isInstalled && isVersionSatisfactory;
22 23 24 25 26

  String _xcodeSelectPath;
  String get xcodeSelectPath {
    if (_xcodeSelectPath == null) {
      try {
27 28 29
        _xcodeSelectPath = processUtils.runSync(
          <String>['/usr/bin/xcode-select', '--print-path'],
        ).stdout.trim();
30 31
      } on ProcessException {
        // Ignored, return null below.
32 33
      } on ArgumentError {
        // Ignored, return null below.
34 35 36 37 38 39
      }
    }
    return _xcodeSelectPath;
  }

  bool get isInstalled {
40
    if (xcodeSelectPath == null || xcodeSelectPath.isEmpty) {
41
      return false;
42
    }
43 44 45 46 47 48 49 50 51 52 53 54 55 56
    return xcodeProjectInterpreter.isInstalled;
  }

  int get majorVersion => xcodeProjectInterpreter.majorVersion;

  int get minorVersion => xcodeProjectInterpreter.minorVersion;

  String get versionText => xcodeProjectInterpreter.versionText;

  bool _eulaSigned;
  /// Has the EULA been signed?
  bool get eulaSigned {
    if (_eulaSigned == null) {
      try {
57 58 59 60
        final RunResult result = processUtils.runSync(
          <String>['/usr/bin/xcrun', 'clang'],
        );
        if (result.stdout != null && result.stdout.contains('license')) {
61
          _eulaSigned = false;
62
        } else if (result.stderr != null && result.stderr.contains('license')) {
63
          _eulaSigned = false;
64
        } else {
65
          _eulaSigned = true;
66
        }
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
      } on ProcessException {
        _eulaSigned = false;
      }
    }
    return _eulaSigned;
  }

  bool _isSimctlInstalled;

  /// Verifies that simctl is installed by trying to run it.
  bool get isSimctlInstalled {
    if (_isSimctlInstalled == null) {
      try {
        // This command will error if additional components need to be installed in
        // xcode 9.2 and above.
82 83 84
        final RunResult result = processUtils.runSync(
          <String>['/usr/bin/xcrun', 'simctl', 'list'],
        );
85 86 87 88 89 90 91 92 93
        _isSimctlInstalled = result.stderr == null || result.stderr == '';
      } on ProcessException {
        _isSimctlInstalled = false;
      }
    }
    return _isSimctlInstalled;
  }

  bool get isVersionSatisfactory {
94
    if (!xcodeProjectInterpreter.isInstalled) {
95
      return false;
96 97
    }
    if (majorVersion > kXcodeRequiredVersionMajor) {
98
      return true;
99 100
    }
    if (majorVersion == kXcodeRequiredVersionMajor) {
101
      return minorVersion >= kXcodeRequiredVersionMinor;
102
    }
103 104 105 106
    return false;
  }

  Future<RunResult> cc(List<String> args) {
107 108 109 110
    return processUtils.run(
      <String>['xcrun', 'cc', ...args],
      throwOnError: true,
    );
111 112 113
  }

  Future<RunResult> clang(List<String> args) {
114 115 116 117
    return processUtils.run(
      <String>['xcrun', 'clang', ...args],
      throwOnError: true,
    );
118 119
  }

120
  Future<String> iPhoneSdkLocation() async {
121
    final RunResult runResult = await processUtils.run(
122
      <String>['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'],
123
      throwOnError: true,
124 125 126 127 128
    );
    if (runResult.exitCode != 0) {
      throwToolExit('Could not find iPhone SDK location: ${runResult.stderr}');
    }
    return runResult.stdout.trim();
129 130
  }

131
  String getSimulatorPath() {
132
    if (xcodeSelectPath == null) {
133
      return null;
134
    }
135 136 137 138 139 140 141 142 143
    final List<String> searchPaths = <String>[
      fs.path.join(xcodeSelectPath, 'Applications', 'Simulator.app'),
    ];
    return searchPaths.where((String p) => p != null).firstWhere(
      (String p) => fs.directory(p).existsSync(),
      orElse: () => null,
    );
  }
}