Repository: pex-tool/pex

Issue:
Pex fails when an expected pip log doesn't exist
This reproduces the problem on an aarch64 machine (but not on other platforms):

```
$ PEX_VERBOSE=1 python3.7  -m pex --interpreter-constraint $'CPython<3.10,>=3.7' pex==2.1.112   --resolver-version pip-2020-resolver --preserve-pip-download-log

...

  File "/home/gha/pex/pex/pip/log_analyzer.py", line 97, in _check_returncode
    with open(self._log, "r") as fp:
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pex-pip-log.5vrr25lt/pip.log'
[Errno 2] No such file or directory: '/tmp/pex-pip-log.5vrr25lt/pip.log'
```

Some logs are written (you can see them with `--preserve-pip-download-log`) but there is always one that isn't. Unclear why, or under what conditions.


Discussion:

Resolving patch:
diff --git a/pex/pip/log_analyzer.py b/pex/pip/log_analyzer.py
--- a/pex/pip/log_analyzer.py
+++ b/pex/pip/log_analyzer.py
@@ -92,21 +92,25 @@ def _check_returncode(self, stderr=None):
         ]
         if activated_analyzers:
             collected = []
-            with open(self._log, "r") as fp:
-                for line in fp:
-                    if not activated_analyzers:
-                        break
-                    for index, analyzer in enumerate(activated_analyzers):
-                        result = analyzer.analyze(line)
-                        if isinstance(result.data, ErrorMessage):
-                            collected.append(result.data)
-                        if isinstance(result, LogAnalyzer.Complete):
-                            activated_analyzers.pop(index).analysis_completed()
-                            if not activated_analyzers:
-                                break
-            for analyzer in activated_analyzers:
-                analyzer.analysis_completed()
-            if not self._preserve_log:
-                os.unlink(self._log)
-            stderr = (stderr or b"") + "".join(collected).encode("utf-8")
+            # A process may fail so early that there is no log file to analyze.
+            # We assume that if this is the case, the superclass _check_returncode will
+            # express the underlying cause of that failure in a way useful to the user.
+            if os.path.isfile(self._log):
+                with open(self._log, "r") as fp:
+                    for line in fp:
+                        if not activated_analyzers:
+                            break
+                        for index, analyzer in enumerate(activated_analyzers):
+                            result = analyzer.analyze(line)
+                            if isinstance(result.data, ErrorMessage):
+                                collected.append(result.data)
+                            if isinstance(result, LogAnalyzer.Complete):
+                                activated_analyzers.pop(index).analysis_completed()
+                                if not activated_analyzers:
+                                    break
+                for analyzer in activated_analyzers:
+                    analyzer.analysis_completed()
+                if not self._preserve_log:
+                    os.unlink(self._log)
+                stderr = (stderr or b"") + "".join(collected).encode("utf-8")
         super(LogScrapeJob, self)._check_returncode(stderr=stderr)


Test patch: