CocoaPods / fourflusher

A library for interacting with Xcode simulators.
MIT License
32 stars 15 forks source link

fetch_sims fails when Xcode 11 beta 4 is installed #25

Closed wojciechczerski closed 4 years ago

wojciechczerski commented 4 years ago

Hello everyone! I am observing errors with pod lib lint command that is running on our CI system that has Xcode 11 beta 4 installed (the project is build using Xcode 10.2.1). The new beta was released on July 17 and if it introduces new simulators list format, it could explain why this error seems to appear suddenly. Here is the error I see:

- ERROR | [iOS] unknown: Encountered an unknown error (784: unexpected token at '2019-07-21 04:16:06.554 xcodebuild[18065:179876] [MT] DVTFirstLaunchPackageInstallationHelper: Skipping all packages via default: DVTSkipFirstLaunchFrameworkVersionChecking
'
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/json/common.rb:156:in `parse'
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/json/common.rb:156:in `parse'
/Library/Ruby/Gems/2.3.0/gems/fourflusher-2.3.1/lib/fourflusher/find.rb:125:in `fetch_sims'
/Library/Ruby/Gems/2.3.0/gems/fourflusher-2.3.1/lib/fourflusher/find.rb:101:in `usable_simulators'
/Library/Ruby/Gems/2.3.0/gems/fourflusher-2.3.1/lib/fourflusher/find.rb:97:in `simulator'
/Library/Ruby/Gems/2.3.0/gems/fourflusher-2.3.1/lib/fourflusher/xcodebuild.rb:7:in `destination'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:993:in `xcodebuild'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:672:in `block in build_pod'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/user_interface.rb:145:in `message'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:663:in `build_pod'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:389:in `block in perform_extensive_analysis'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:377:in `each'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:377:in `perform_extensive_analysis'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/validator.rb:128:in `validate'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/command/lib/lint.rb:86:in `block in run'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/command/lib/lint.rb:69:in `each'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/command/lib/lint.rb:69:in `run'
/Library/Ruby/Gems/2.3.0/gems/claide-1.0.2/lib/claide/command.rb:334:in `run'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/lib/cocoapods/command.rb:52:in `run'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.7.5/bin/pod:55:in `<top (required)>'
/usr/local/bin/pod:22:in `load'
/usr/local/bin/pod:22:in `<main>'

I am downloading the latest beta right now, but my assumption is that Apple has changed the simulators list format again, which is causing fetch_sims to fail. I will provide an update if I am able to reproduce the issue locally after the beta is installed.

wojciechczerski commented 4 years ago

While 7,6 GB of Xcode are downloading, I've executed xcrun simctl list --json command on the CI machine and the output is:

2019-07-21 04:55:41.259 xcodebuild[2927:12763] [MT] DVTFirstLaunchPackageInstallationHelper: Skipping all packages via default: DVTSkipFirstLaunchFrameworkVersionChecking
{
  "devicetypes" : [
    {
      "name" : "iPhone 4s",
      "bundlePath" : "\/Applications\/Xcode-10.2.1.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Developer\/Library\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 4s.simdevicetype",
      "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-4s"
    },
    {
      "name" : "iPhone 5",
      "bundlePath" : "\/Applications\/Xcode-10.2.1.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Developer\/Library\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 5.simdevicetype",
      "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5"
    },
(...)

So it's not about the format but the crazy first line in the JSON output which is obviously not a valid JSON:

2019-07-21 04:55:41.259 xcodebuild[2927:12763] [MT] DVTFirstLaunchPackageInstallationHelper: Skipping all packages via default: DVTSkipFirstLaunchFrameworkVersionChecking

Still I'll check it locally to verify that it's indeed related with Xcode 11 beta or maybe it's just a weirdness of the CI I'm using.

dnkoutso commented 4 years ago

Looks like your environment:

~/Development/ios xcodebuild -version
Xcode 11.0
Build version 11M374r
~/Development/ios xcrun simctl list --json
{
  "devicetypes" : [
    {
      "name" : "iPhone 4s",
      "bundlePath" : "\/Applications\/Xcode-beta.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 4s.simdevicetype",
      "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-4s"
    },
    {
      "name" : "iPhone 5",
      "bundlePath" : "\/Applications\/Xcode-beta.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 5.simdevicetype",
      "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-5"
    },
...
}

Closing for now and we can re-open if we truly find an issue. We have also not seen other reports here and its been a few days since Xcode 11 Beta 4 came out.

wojciechczerski commented 4 years ago

Thanks for checking this out and sorry for creating noise. I confirm that locally there is no extra outputs when executing this command so all is fine.

stephenyao commented 4 years ago

Hi there, I'm also experiencing the same issue on my CI (Buddybuild). I've run xcrun simctl list devices -j and have the following output from CI logs:

2019-07-22T13:36:19.304Z - ce:     2019-07-22 06:36:19.270 xcodebuild[1770:8837] [MT] DVTFirstLaunchPackageInstallationHelper: Skipping all packages via default: DVTSkipFirstLaunchFrameworkVersionChecking
{
    "devices": {
        "com.apple.CoreSimulator.SimRuntime.iOS-9-3": [
            {
                "state": "Shutdown",
                "isAvailable": true,
                "name": "iPhone 4s",
                "udid": "8767D263-AB45-43E5-8997-4E07F2621CAB"
            },
            {
                "state": "Shutdown",
                "isAvailable": true,
                "name": "iPhone 5",
                "udid": "52EE30F9-0269-4E01-B9BE-75615246EDC7"
            }
...
}

I've also run xcodebuild -version and can confirm from logs that the selected version is Xcode 10.2.1. Cannot reproduce this on local machine which also has Xcode 11 beta 4 installed (MacOS Catalina). Maybe it is because the CI machine is running Mojave? That's the only thing I can think of at the moment. Wondering if OP had any progress with this, and if not, whether we could re-open the issue? Thanks.

stephenyao commented 4 years ago

Update: Just ran the xcrun simctl list devices -j on a Mojave machine that also has Xcode 11 beta 4 installed, and could not replicate the issue. Not sure what type of machine the CI has that causes the first line of the command to be that weird gibberish that's obviously not json. Please let me know if there's any leads

churowa commented 4 years ago

This is happening because while simctl is outputting the JSON on standard out, xcrun is also outputting extra information on standard error.

You can suppress the latter by adding 2>/dev/null to the end of the list devices call.

xcrun simctl list devices -j 2>/dev/null

stephenyao commented 4 years ago

Thanks for replying. I've updated fourflusher to use a local fork where I provide the 2>dev/null option, to the fetch_sims method as such: device_list = JSON.parse(list(['-j', 'devices', '2>/dev/null']))['devices']

However, I'm still getting the same error.

When I ran xcrun simctl list devices -j 2>/dev/null on the CI as a post clone it did indeed remove the first line around DVTSkipFirstLaunchFrameworkVersionChecking, but it doesn't seem to be doing that when fourflusher is running the command.

stephenyao commented 4 years ago

Have also tried directly modifying the simctl! method in simctl.rb:

def simctl!(args)
  xcrun!(['simctl'] + args + ['2>/dev/null'])
end

And it's also still logging the xcrun output to standard error. Hoping to get some help on this, being not proficient in Ruby

wojciechczerski commented 4 years ago

@stephenyao I also tried appending 2>/dev/null in the places you pointed out and of course it didn't work for me as well. I did some further research and I've found this line: https://github.com/CocoaPods/fourflusher/blob/master/lib/fourflusher/executable.rb#L98

With my poor understanding of Ruby I suspect that Executable.execute_command captures and outputs both stdout and stderr. A suspect a change has to be done in this file. I'm testing it right now and will write back if it succeeds (or fails).

stephenyao commented 4 years ago

Thanks @wojciechczerski, I'm also running some tests there. I've tried appending that parameter directly to the full_command string, but still hasn't achieved any outcome:

def self.execute_command(executable, command, raise_on_failure = true)
  bin = which(executable)
  fail Fourflusher::Informative, "Unable to locate the executable `#{executable}`" unless bin

  command = command.map(&:to_s)
  full_command = "#{bin} #{command.join(' ')} >2/dev/null"
  ...
end

Will report back on further findings if I have any.

stephenyao commented 4 years ago

I found that if we comment out the stderror in the output on line 98 of executable.rb, then it would succeed:

def self.execute_command(executable, command, raise_on_failure = true)
  ...
  stdout = stdout.join
  stderr = stderr.join
  output = stdout
  ...
end

This is not the best way to do it, I'm hoping to find some other ways to suppress the error. But at least we'll have a working build for now.

wojciechczerski commented 4 years ago

@stephenyao I think I have a solution / workaround.

  1. In the fourflusher/executable.rb:
def self.execute_command(executable, command, raise_on_failure = true, output_stderr = true)
  bin = which(executable)
  fail Fourflusher::Informative, "Unable to locate the executable `#{executable}`" unless bin

  command = command.map(&:to_s)
  full_command = "#{bin} #{command.join(' ')}"

  if Config.instance.verbose?
    UI.message("$ #{full_command}")
    stdout = Indenter.new(STDOUT)
    stderr = Indenter.new(STDERR)
  else
    stdout = Indenter.new
    stderr = Indenter.new
  end

  status = popen3(bin, command, stdout, stderr)
  stdout = stdout.join
  stderr = stderr.join
  output = stdout

  if output_stderr
    output += stderr
  end

  unless status.success?
    if raise_on_failure
      fail Fourflusher::Informative, "#{full_command}\n\n#{output}"
    else
      UI.message("[!] Failed: #{full_command}".red)
    end
  end

  output
end

The diff here is the new output_stderr parameter and the conditional:

if output_stderr
  output += stderr
end

Then in the same file I defined another method (see line 52):

define_method(name.to_s + '_') do |*command|
  Executable.execute_command(name, Array(command).flatten, true, false)
end
  1. In the fourflusher/simctl.rb modify the def simctl!(args) method:
def simctl!(args)
  xcrun_(['simctl'] + args)
end

The new xcrun_ method is called instead of the xcrun!.

Hope that works for you as well.

stephenyao commented 4 years ago

Great! Thanks for that, I'll be applying something similar to get around the build issues. All the best.