Bug 1384241 - Review comment: Close the pywatchman client; abstract away pywatchman errors. r=gps draft
authorNick Alexander <nalexander@mozilla.com>
Wed, 26 Jul 2017 16:58:28 -0700
changeset 616496 fa928c88094fbb87cad3e461eaf92cade510be0b
parent 616495 9c44680ab95a60ed60d202c1a2f5c6c4128ba837
child 616497 3d3a048ec518daa3e855300b47c5d4938e7482de
push id70704
push usernalexander@mozilla.com
push dateThu, 27 Jul 2017 03:35:28 +0000
reviewersgps
bugs1384241
milestone56.0a1
Bug 1384241 - Review comment: Close the pywatchman client; abstract away pywatchman errors. r=gps MozReview-Commit-ID: 3KjfacoHPE3
python/mozbuild/mozbuild/faster_daemon.py
--- a/python/mozbuild/mozbuild/faster_daemon.py
+++ b/python/mozbuild/mozbuild/faster_daemon.py
@@ -45,16 +45,22 @@ def print_copy_result(elapsed, destdir, 
         elapsed=elapsed,
         dest=destdir,
         existing=result.existing_files_count,
         updated=result.updated_files_count,
         rm_files=result.removed_files_count,
         rm_dirs=result.removed_directories_count))
 
 
+class FasterBuildException(Exception):
+    def __init__(self, cause):
+        Exception.__init__(self)
+        self.cause = cause
+
+
 class FasterBuildChange(object):
     def __init__(self):
         self.unrecognized = set()
         self.input_to_outputs = {}
         self.output_to_inputs = {}
 
 
 class Daemon(object):
@@ -193,58 +199,71 @@ class Daemon(object):
 
     def input_changes(self):
         '''
         Return an iterator of `FasterBuildChange` instances as inputs
         to the faster build system change.
         '''
 
         self.client = pywatchman.client()
-        # TODO: restrict these capabilities to the minimal set.
-        self.client.capabilityCheck(required=['term-dirname', 'cmd-watch-project', 'wildmatch'])
+
+        try:
+            # TODO: restrict these capabilities to the minimal set.
+            self.client.capabilityCheck(required=['term-dirname', 'cmd-watch-project', 'wildmatch'])
 
-        for watch in sorted(self.watch_set()):
-            name = watch
-            path = mozpath.join(self.config_environment.topsrcdir, watch)
-            sub = self.subscribe_to_dir(name, path)
-            self._subscriptions.append(sub)
+            for watch in sorted(self.watch_set()):
+                name = watch
+                path = mozpath.join(self.config_environment.topsrcdir, watch)
+                sub = self.subscribe_to_dir(name, path)
+                self._subscriptions.append(sub)
 
-        input_to_outputs = self.file_copier.input_to_outputs_tree()
-        for input, outputs in input_to_outputs.items():
-            if not outputs:
-                raise Exception("Refusing to watch input ({}) with no outputs".format(input))
+            input_to_outputs = self.file_copier.input_to_outputs_tree()
+            for input, outputs in input_to_outputs.items():
+                if not outputs:
+                    raise Exception("Refusing to watch input ({}) with no outputs".format(input))
 
-        while True:
-            try:
-                _watch_result = self.client.receive()
+            while True:
+                try:
+                    _watch_result = self.client.receive()
+
+                    changed = self.changed_files()
+                    if not changed:
+                        continue
+
+                    result = FasterBuildChange()
 
-                changed = self.changed_files()
-                if not changed:
-                    continue
+                    for change in changed:
+                        change = mozpath.normpath(change)
+                        if change in input_to_outputs:
+                            result.input_to_outputs[change] = set(input_to_outputs[change])
+                        else:
+                            result.unrecognized.add(change)
 
-                result = FasterBuildChange()
+                    for input, outputs in result.input_to_outputs.items():
+                        for output in outputs:
+                            if output not in result.output_to_inputs:
+                                result.output_to_inputs[output] = set()
+                            result.output_to_inputs[output].add(input)
+
+                    yield result
 
-                for change in changed:
-                    change = mozpath.normpath(change)
-                    if change in input_to_outputs:
-                        result.input_to_outputs[change] = set(input_to_outputs[change])
-                    else:
-                        result.unrecognized.add(change)
+                except pywatchman.SocketTimeout:
+                    # Let's check to see if we're still functional.
+                    _version = self.client.query('version')
 
-                for input, outputs in result.input_to_outputs.items():
-                    for output in outputs:
-                        if output not in result.output_to_inputs:
-                            result.output_to_inputs[output] = set()
-                        result.output_to_inputs[output].add(input)
+        except pywatchman.CommandError as e:
+            # Abstract away pywatchman errors.
+            raise FasterBuildException(e)
 
-                yield result
+        except pywatchman.SocketTimeout as ex:
+            # Abstract away pywatchman errors.
+            raise FasterBuildException(e)
 
-            except pywatchman.SocketTimeout:
-                # Let's check to see if we're still functional.
-                _version = self.client.query('version')
+        finally:
+            self.client.close()
 
     def output_changes(self, verbose=True):
         '''
         Return an iterator of `FasterBuildChange` instances as outputs
         from the faster build system are updated.
         '''
         # TODO: consider how to really provide the debug diagnostics
         # we want, since this print is not interleaved with the
@@ -271,27 +290,8 @@ class Daemon(object):
 
             if all_outputs:
                 partial_copier = FileCopier()
                 for output in all_outputs:
                     partial_copier.add(output, self.file_copier[output])
 
                 self.incremental_copy(partial_copier, force=True, verbose=verbose)
                 yield change
-
-    def watch(self, verbose=True):
-        try:
-            for change in self.output_changes(verbose=verbose):
-                pass
-
-        except pywatchman.CommandError as ex:
-            print('watchman:', ex.msg, file=sys.stderr)
-            sys.exit(1)
-
-        except pywatchman.SocketTimeout as ex:
-            print('watchman:', str(ex), file=sys.stderr)
-            sys.exit(2)
-
-        except KeyboardInterrupt:
-            # Suppress ugly stack trace when user hits Ctrl-C.
-            sys.exit(3)
-
-        return 0