def test_chain_with_resolved(self): def worker(resolve_fn): resolve_fn(999) def assertResult(result): self.assertEqual(result, 999) promise = Promise(worker) self.assertTrue(promise._is_resolved()) promise2 = promise.then(assertResult) self.assertTrue(promise2._is_resolved())
def test_chain_with_pending(self): def worker_async(resolve_fn): sublime.set_timeout_async(lambda: resolve_fn(999), 100) def assertResult(result): self.assertEqual(result, 999) promise = Promise(worker_async) self.assertFalse(promise._is_resolved()) promise2 = promise.then(assertResult) self.assertFalse(promise2._is_resolved()) # Let promises resolve. time.sleep(0.2) self.assertTrue(promise._is_resolved())
def git_current_branch(self): """Query the current branch of the file's repository.""" if self._git_branch: return Promise.resolve(self._git_branch) def cache_result(branch): self._git_branch = branch return branch args = [settings.git_binary_path, 'rev-parse', '--abbrev-ref', 'HEAD'] return self.run_command(args).then(cache_result)
def test_chain_with_promise(self): def worker_async(resolve_fn): sublime.set_timeout_async(lambda: resolve_fn(999), 100) def worker_async2(resolve_fn): sublime.set_timeout_async(lambda: resolve_fn(888), 100) def callback(async_value): self.assertEqual(async_value, 999) return Promise(worker_async2) def verify_async2_value(value): self.assertEqual(value, 888) promise = Promise(worker_async) self.assertFalse(promise._is_resolved()) promise2 = promise.then(callback) self.assertFalse(promise2._is_resolved()) promise2.then(verify_async2_value) # Let both promises resolve. time.sleep(0.500) self.assertTrue(promise._is_resolved()) self.assertEqual(promise._get_value(), 999) self.assertTrue(promise2._is_resolved()) self.assertEqual(promise2._get_value(), 888)
def run_command(self, args, decode=True): """Run a git command asynchronously and return a Promise. Arguments: args - a list of arguments used to create the git subprocess. decode - if True the git's output is decoded assuming utf-8 which is the default output encoding of git. """ def read_output(resolve): """Start git process and forward its output to the Resolver.""" stdout, stderr = None, None try: if os.name == 'nt': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW else: startupinfo = None proc = subprocess.Popen(args=args, cwd=self._git_tree, startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) if _HAVE_TIMEOUT: stdout, stderr = proc.communicate(timeout=30) else: stdout, stderr = proc.communicate() except OSError as error: # print out system error message print('GitGutter: \'git %s\' failed with \"%s\"' % (args[1], error)) except TimeoutExpired: proc.kill() stdout, stderr = proc.communicate() finally: if stderr and stderr.startswith(b'fatal:'): # print out git's error message print('GitGutter: \'git %s\' failed with \"%s\"' % (args[1], stderr.decode('utf-8').strip())) if stdout and decode: # resolve with string value resolve(stdout.decode('utf-8').strip()) else: # resolve with binary value resolve(stdout) def run_async(resolve): set_timeout(lambda: read_output(resolve), 10) return Promise(run_async)
def check_commit(commit): """Check if compare target changed and update git file then. If the commit has didn't change since the last run, the temporary file is still up to date and git 'show' can be skipped and the promise is resolved with False. This method uses `git archive` to read the file content from git repository to enable support of smudge filters (fixes Issue #74). Git applies those smudge filters to some commands like `archive`, `diff` and `checkout` only, but not to commands like `show`. Arguments: commit (string): full hash of the commit the view is currently compared against. Returns: bool: True if temporary file was updated, False otherwise. """ def write_file(contents): """Extract output and write it to a temporary file. The function resolves the promise with True to indicate the updated git file. """ try: # Mangle end of lines contents = contents.replace(b'\r\n', b'\n') contents = contents.replace(b'\r', b'\n') # Write the content to file if not self._git_temp_file: self._git_temp_file = self.tmp_file() with open(self._git_temp_file, 'wb') as file: file.write(contents) self.git_tracked = True self._git_compared_commit = commit return True except AttributeError: # Git returned empty output, file is not tracked self.git_tracked = False self._git_compared_commit = commit return False except OSError as error: print('GitGutter failed to create git cache: %s' % error) return False # Read file from git incase the compare target has changed if self._git_compared_commit == commit: return Promise.resolve(False) return self.git_read_file(commit).then(write_file)
def check_commit(commit): """Check if compare target changed and update git file then. If the commit has didn't change since the last run, the temporary file is still up to date and git 'show' can be skipped and the promise is resolved with False. This method uses `git archive` to read the file content from git repository to enable support of smudge filters (fixes Issue #74). Git applies those smudge filters to some commands like `archive`, `diff` and `checkout` only, but not to commands like `show`. Arguments: commit (string): full hash of the commit the view is currently compared against. Returns: bool: True if temporary file was updated, False otherwise. """ def write_file(output): """Extract output and write it to a temporary file. The function resolves the promise with True to indicate the updated git file. """ contents = b'' if output: # Extract file contents from zipped archive. # The `filelist` contains numberous directories finalized # by exactly one file whose content we are interested in. archive = zipfile.ZipFile(BytesIO(output)) contents = archive.read(archive.filelist[-1]) # Write the content to file if not self._git_temp_file: self._git_temp_file = self.tmp_file() with open(self._git_temp_file, 'wb') as file: file.write(contents) # finally update git hash if file was updated self._git_compared_commit = commit self.git_tracked = bool(contents) return True # Read file from git incase the compare target has changed if self._git_compared_commit == commit: return Promise.resolve(False) return self.git_read_file(commit).then(write_file)
def run_command(self, args, decode=True): """Run a git command asynchronously and return a Promise. Arguments: args - a list of arguments used to create the git subprocess. decode - if True the git's output is decoded assuming utf-8 which is the default output encoding of git. """ def read_output(resolve): """Start git process and forward its output to the Resolver.""" try: if os.name == 'nt': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW else: startupinfo = None proc = subprocess.Popen(args=args, cwd=self._git_tree, startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) if _HAVE_TIMEOUT: stdout, stderr = proc.communicate(timeout=30) else: stdout, stderr = proc.communicate() except OSError as error: print('GitGutter failed to run git: %s' % error) stdout = b'' except TimeoutExpired: proc.kill() stdout, stderr = proc.communicate() finally: if decode: resolve(stdout.decode('utf-8').strip()) else: resolve(stdout) def run_async(resolve): set_timeout(lambda: read_output(resolve), 10) return Promise(run_async)
def run_diff(updated_git_file): # if both temp files were not updated, diff is not necessary. # Resolve with None to indicate this special situation. updated_view_file = self.update_view_file() if not updated_view_file and not updated_git_file: return Promise.resolve(None) args = [ settings.git_binary_path, 'diff', '-U0', '--no-color', '--no-index', settings.ignore_whitespace, settings.patience_switch, self._git_temp_file, self._view_temp_file, ] args = list(filter(None, args)) # Remove empty args return self.run_command(args=args, decode=False).then(decode_diff)
def handle_files(self, additional_args): """Run git ls-files to check for untracked or ignored file.""" if self._git_tree: def is_nonempty(results): """Determine if view's file is in git's index. If the view's file is not part of the index git returns empty output to stdout. """ return bool(results) args = [ settings.git_binary_path, 'ls-files', '--other', '--exclude-standard', ] + additional_args + [ os.path.join(self._git_tree, self._git_path), ] args = list(filter(None, args)) # Remove empty args return self.run_command(args).then(is_nonempty) return Promise.resolve(False)
def callback(async_value): self.assertEqual(async_value, 999) return Promise(worker_async2)
def test_promise_resolve(self): promise = Promise.resolve(999) self.assertTrue(promise._is_resolved()) self.assertEqual(promise._get_value(), 999)