def do_test(): golangconfig.subprocess_info( executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window )
def subprocess_info(cls, name, view): """Query the subprocess info for a given go command. :param str name: Name of the command. :param sublime.View view: Current editor view. :returns: (str, dict(str, str)) Returns the path to the executable and a dictionary of environment variables that should be passed to the process when run. :raises RuntimeError: if called from a non-main thread. """ view_subprocess_info = cls._views_subprocess_info[view.id()] subprocess_info = view_subprocess_info.get(name) if subprocess_info is not None: return subprocess_info if not is_main_thread(): # golangconfig requires that settings only be accessed from the # main thread, so we can't do anything at this point. raise RuntimeError( 'subprocess_info for {} is not cached, and cannot be created' '(because this is not the main thread)'.format(name)) subprocess_info = golangconfig.subprocess_info(name, REQUIRED_VARS, OPTIONAL_VARS, view, view.window()) view_subprocess_info[name] = subprocess_info return subprocess_info
def run(view, tool, args=[], stdin=None, timeout=5, cwd=None): toolpath, env = golangconfig.subprocess_info(tool, ['GOPATH', 'PATH'], view=view) cmd = [toolpath] + args try: Logger.log("spawning process...") Logger.log("\tcommand: " + " ".join(cmd)) # Logger.log("\tenvironment: " + str(env)) # Hide popups on Windows si = None if platform.system() == "Windows": si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW start = time.time() p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, startupinfo=si, cwd=cwd) stdout, stderr = p.communicate(input=stdin, timeout=timeout) p.wait(timeout=timeout) elapsed = round(time.time() - start) Logger.log("process returned ({0}) in {1} seconds".format( str(p.returncode), str(elapsed))) stderr = stderr.decode("utf-8") if len(stderr) > 0: Logger.log("stderr:\n{0}".format(stderr)) return stdout.decode("utf-8"), stderr, p.returncode except subprocess.CalledProcessError as e: raise
def __init__(self, cmd, view, window): self.view = view self.window = window self.name = cmd[0] self.args = cmd[1:] self.path, self.env = golangconfig.subprocess_info( self.name, REQUIRED_VARS, OPTIONAL_VARS, self.view, self.window)
def run(view, tool, args=[], stdin=None, timeout=5, cwd=None): toolpath, env = golangconfig.subprocess_info(tool, ['GOPATH', 'PATH'], view=view) cmd = [toolpath] + args try: Logger.log("spawning process...") Logger.log("\tcommand: " + " ".join(cmd)) # Logger.log("\tenvironment: " + str(env)) # Hide popups on Windows si = None if platform.system() == "Windows": si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW start = time.time() p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, startupinfo=si, cwd=cwd) stdout, stderr = p.communicate(input=stdin, timeout=timeout) p.wait(timeout=timeout) elapsed = round(time.time() - start) Logger.log("process returned ({0}) in {1} seconds".format(str(p.returncode), str(elapsed))) stderr = stderr.decode("utf-8") if len(stderr) > 0: Logger.log("stderr:\n{0}".format(stderr)) return stdout.decode("utf-8"), stderr, p.returncode except subprocess.CalledProcessError as e: raise
def guru(self, end_offset, begin_offset=None, mode="describe", callback=None): """ Builds the guru shell command and calls it, returning it's output as a string. """ pos = "#" + str(end_offset) if begin_offset is not None: pos = "#%i,#%i" %(begin_offset, end_offset) file_path = self.view.file_name() # golang config or shellenv ? cmd_env = '' if use_golangconfig: try: toolpath, cmd_env = golangconfig.subprocess_info('guru', ['GOPATH', 'PATH'], view=self.view) toolpath = os.path.realpath(toolpath) except: error("golangconfig:", sys.exc_info()) return else: toolpath = 'guru' cmd_env = shellenv.get_env(for_subprocess=True)[1] cmd_env.update(get_setting("env", {})) debug("env", cmd_env) guru_scope = ",".join(get_setting("guru_scope", "")) # add local package to guru scope if get_setting("use_current_package", True) : current_file_path = os.path.realpath(os.path.dirname(file_path)) GOPATH = os.path.realpath(cmd_env["GOPATH"]) GOPATH = os.path.join(GOPATH,"src") local_package = os.path.relpath(current_file_path, GOPATH) if sublime.platform() == 'windows': local_package = local_package.replace('\\', '/') debug("GOPATH", GOPATH) debug("local_package", local_package) guru_scope = guru_scope+','+local_package guru_scope = guru_scope.strip() debug("guru_scope", guru_scope) if len(guru_scope) > 0: guru_scope = "-scope "+guru_scope guru_json = "" if get_setting("guru_json", False): guru_json = "-json" # Build guru cmd. cmd = "%(toolpath)s %(scope)s %(guru_json)s %(mode)s %(file_path)s:%(pos)s" % { "toolpath": toolpath, "file_path": file_path, "pos": pos, "guru_json": guru_json, "mode": mode, "scope": guru_scope} debug("cmd", cmd) sublime.set_timeout_async(lambda: self.runInThread(cmd, callback, cmd_env), 0)
def test_subprocess_info_goroot_executable_not_inside(self): shell = '/bin/bash' env = { 'PATH': '{tempdir}bin:{tempdir}go/bin', 'GOPATH': '{tempdir}workspace', 'GOROOT': '{tempdir}go' } with GolangConfigMock(shell, env, None, None, {}) as mock_context: mock_context.replace_tempdir_env() mock_context.replace_tempdir_view_settings() mock_context.replace_tempdir_window_settings() mock_context.make_executable_files(['bin/go', 'go/bin/go']) mock_context.make_dirs(['workspace']) golangconfig.subprocess_info('go', ['GOPATH'], optional_vars=['GOROOT'], view=mock_context.view, window=mock_context.window) self.assertTrue( 'which is not inside of the GOROOT' in sys.stdout.getvalue())
def test_subprocess_info_goroot_executable_not_inside(self): shell = '/bin/bash' env = { 'PATH': '{tempdir}bin:{tempdir}go/bin', 'GOPATH': '{tempdir}workspace', 'GOROOT': '{tempdir}go' } with GolangConfigMock(shell, env, None, None, {}) as mock_context: mock_context.replace_tempdir_env() mock_context.replace_tempdir_view_settings() mock_context.replace_tempdir_window_settings() mock_context.make_executable_files(['bin/go', 'go/bin/go']) mock_context.make_dirs(['workspace']) golangconfig.subprocess_info( 'go', ['GOPATH'], optional_vars=['GOROOT'], view=mock_context.view, window=mock_context.window ) self.assertTrue('which is not inside of the GOROOT' in sys.stdout.getvalue())
def subprocess_info(self, shell, env, view_settings, window_settings, sublime_settings, executable_temp_files, temp_dirs, executable_name, required_vars, optional_vars, expected_result): with GolangConfigMock(shell, env, view_settings, window_settings, sublime_settings) as mock_context: mock_context.replace_tempdir_env() mock_context.replace_tempdir_view_settings() mock_context.replace_tempdir_window_settings() mock_context.replace_tempdir_sublime_settings() mock_context.make_executable_files(executable_temp_files) mock_context.make_dirs(temp_dirs) if isinstance(expected_result, tuple): tempdir = mock_context.tempdir + os.sep executable_path = expected_result[0].replace( '{tempdir}', tempdir) executable_path = shellenv.path_encode(executable_path) env_vars = {} for name, value in expected_result[1].items(): value = value.replace('{tempdir}', tempdir) name = shellenv.env_encode(name) value = shellenv.env_encode(value) env_vars[name] = value expected_result = (executable_path, env_vars) self.assertEquals( expected_result, golangconfig.subprocess_info(executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window)) self.assertEqual('', sys.stdout.getvalue()) else: def do_test(): golangconfig.subprocess_info(executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window) self.assertRaises(expected_result, do_test)
def subprocess_info(self, shell, env, view_settings, window_settings, sublime_settings, executable_temp_files, temp_dirs, executable_name, required_vars, optional_vars, expected_result): with GolangConfigMock(shell, env, view_settings, window_settings, sublime_settings) as mock_context: mock_context.replace_tempdir_env() mock_context.replace_tempdir_view_settings() mock_context.replace_tempdir_window_settings() mock_context.replace_tempdir_sublime_settings() mock_context.make_executable_files(executable_temp_files) mock_context.make_dirs(temp_dirs) if isinstance(expected_result, tuple): tempdir = mock_context.tempdir + os.sep executable_path = expected_result[0].replace('{tempdir}', tempdir) executable_path = shellenv.path_encode(executable_path) env_vars = {} for name, value in expected_result[1].items(): value = value.replace('{tempdir}', tempdir) name = shellenv.env_encode(name) value = shellenv.env_encode(value) env_vars[name] = value expected_result = (executable_path, env_vars) self.assertEquals( expected_result, golangconfig.subprocess_info( executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window ) ) self.assertEqual('', sys.stdout.getvalue()) else: def do_test(): golangconfig.subprocess_info( executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window ) self.assertRaises(expected_result, do_test)
def gorename(self, file_path, begin_offset=None, flags=None, name=None, callback=None): """ Builds the gorename shell command and calls it, returning it's output as a string. """ global runningTool runningTool = True pos = "#" + str(begin_offset) # golangconfig or shellenv ? cmd_env = '' if use_golangconfig: try: toolpath, cmd_env = golangconfig.subprocess_info( 'gorename', ['GOPATH', 'PATH'], view=self.view) toolpath = os.path.realpath(toolpath) except: error("golangconfig:", sys.exc_info()) return else: toolpath = 'gorename' cmd_env = shellenv.get_env(for_subprocess=True)[1] cmd_env.update(get_setting("gorename_env", {})) debug("env", cmd_env) gorename_json = "" if get_setting("gorename_json", False): gorename_json = "-json" # Build gorename cmd. cmd = "%(toolpath)s -offset %(file_path)s:%(pos)s -to %(name)s %(flags)s" % { "toolpath": toolpath, "file_path": file_path, "pos": pos, "name": name, "flags": flags } debug("cmd", cmd) sublime.set_timeout_async( lambda: self.runInThread(cmd, callback, cmd_env), 0)
def run(self, edit, command=None): if not command: Logger.log("command is required") return filename, row, col, offset, offset_end = Buffers.location_at_cursor( self.view) if command == "freevars": pos = filename + ":#" + str(offset) + "," + "#" + str(offset_end) else: pos = filename + ":#" + str(offset) # Build up a package scope contaning all packages the user might have # configured. package_scope = [] project_package = golangconfig.setting_value("project_package", view=self.view)[0] if project_package: if not golangconfig.setting_value("build_packages")[0]: package_scope.append(project_package) else: for p in golangconfig.setting_value("build_packages", view=self.view)[0]: package_scope.append(os.path.join(project_package, p)) # add local package to guru scope if golangconfig.setting_value("guru_use_current_package")[0]: current_file_path = os.path.realpath( os.path.dirname(self.view.file_name())) toolpath, env = golangconfig.subprocess_info('guru', ['GOPATH', 'PATH'], view=self.view) GOPATH = os.path.realpath(env["GOPATH"]) GOPATH = os.path.join(GOPATH, "src") local_package = os.path.relpath(current_file_path, GOPATH) if sublime.platform() == 'windows': local_package = local_package.replace('\\', '/') Logger.status("GOPATH: " + GOPATH) Logger.status("local_package: " + local_package) package_scope.append(local_package) sublime.active_window().run_command("hide_panel", {"panel": "output.gotools_guru"}) self.do_plain_guru(command, pos, package_scope)
def gorename(self, file_path, begin_offset=None, flags=None, name=None, callback=None): """ Builds the gorename shell command and calls it, returning it's output as a string. """ global runningTool runningTool = True pos = "#" + str(begin_offset) # golangconfig or shellenv ? cmd_env = '' if use_golangconfig: try: toolpath, cmd_env = golangconfig.subprocess_info('gorename', ['GOPATH', 'PATH'], view=self.view) toolpath = os.path.realpath(toolpath) except: error("golangconfig:", sys.exc_info()) return else: toolpath = 'gorename' cmd_env = shellenv.get_env(for_subprocess=True)[1] cmd_env.update(get_setting("gorename_env", {})) debug("env", cmd_env) gorename_json = "" if get_setting("gorename_json", False): gorename_json = "-json" # Build gorename cmd. cmd = "%(toolpath)s -offset %(file_path)s:%(pos)s -to %(name)s %(flags)s" % { "toolpath": toolpath, "file_path": file_path, "pos": pos, "name": name, "flags": flags} debug("cmd", cmd) sublime.set_timeout_async(lambda: self.runInThread(cmd, callback, cmd_env), 0)
def run(self, edit): view = self.view try: # Get the view content and encode it content = view.substr(sublime.Region(0, view.size())) encoded_content = content.encode('utf-8') # Find the gofmt executable executable_path, env = golangconfig.subprocess_info( 'gofmt', [], optional_vars=['GOPATH', 'GOROOT'], view=self.view) # Format the content proc = subprocess.Popen('gofmt', executable=executable_path, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate(input=encoded_content) if proc.returncode != 0: self.view.window().status_message( 'GoEasy: Cannot format file — please check for syntax errors' ) return # Decode and patch the view decoded_content = stdout.decode('utf-8') patch_view(self.view, edit, decoded_content) except (golangconfig.ExecutableError) as ex: pass except (golangconfig.GoRootNotFoundError, golangconfig.GoPathNotFoundError) as ex: pass
def run(self, edit, command=None): if not command: Logger.log("command is required") return filename, row, col, offset, offset_end = Buffers.location_at_cursor(self.view) if command == "freevars": pos = filename+":#"+str(offset)+","+"#"+str(offset_end) else: pos = filename+":#"+str(offset) # Build up a package scope contaning all packages the user might have # configured. package_scope = [] project_package = golangconfig.setting_value("project_package", view=self.view)[0] if project_package: if not golangconfig.setting_value("build_packages")[0]: package_scope.append(project_package) else: for p in golangconfig.setting_value("build_packages", view=self.view)[0]: package_scope.append(os.path.join(project_package, p)) # add local package to guru scope if golangconfig.setting_value("guru_use_current_package")[0]: current_file_path = os.path.realpath(os.path.dirname(self.view.file_name())) toolpath, env = golangconfig.subprocess_info('guru', ['GOPATH', 'PATH'], view=self.view) GOPATH = os.path.realpath(env["GOPATH"]) GOPATH = os.path.join(GOPATH,"src") local_package = os.path.relpath(current_file_path, GOPATH) if sublime.platform() == 'windows': local_package = local_package.replace('\\', '/') Logger.status("GOPATH: "+GOPATH) Logger.status("local_package: "+local_package) package_scope.append(local_package) sublime.active_window().run_command("hide_panel", {"panel": "output.gotools_guru"}) self.do_plain_guru(command, pos, package_scope)
def run(view, tool, args=[], stdin=None, timeout=5, cwd=None): toolpath, env = golangconfig.subprocess_info(tool, ['GOPATH', 'PATH'], view=view) return ToolRunner._run(toolpath, env, args, stdin, timeout, cwd)
def _get_config(executable_name, required_vars, optional_vars=None, view=None, window=None): """ :param executable_name: A unicode string of the executable to locate, e.g. "go" or "gofmt" :param required_vars: A list of unicode strings of the environment variables that are required, e.g. "GOPATH". Obtains values from setting_value(). :param optional_vars: A list of unicode strings of the environment variables that are optional, but should be pulled from setting_value() if available - e.g. "GOOS", "GOARCH". Obtains values from setting_value(). :param view: A sublime.View object to use in finding project-specific settings. This should be passed whenever available. :param window: A sublime.Window object to use in finding project-specific settings. This will only work for Sublime Text 3, and should only be passed if no sublime.View object is available to pass via the view parameter. :return: A two-element tuple. If there was an error finding the executable or required vars: - [0] None - [1] None Otherwise: - [0] A string of the path to the executable - [1] A dict of environment variables for the executable """ try: return golangconfig.subprocess_info(executable_name, required_vars, optional_vars, view=view, window=window) except (golangconfig.ExecutableError) as e: error_message = ''' Golang Build The %s executable could not be found. Please ensure it is installed and available via your PATH. Would you like to view documentation for setting a custom PATH? ''' prompt = error_message % e.name if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', { 'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md' }) except (golangconfig.EnvVarError) as e: error_message = ''' Golang Build The setting%s %s could not be found in your Sublime Text settings or your shell environment. Would you like to view the configuration documentation? ''' plural = 's' if len(e.missing) > 1 else '' setting_names = ', '.join(e.missing) prompt = error_message % (plural, setting_names) if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', { 'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md' }) except (golangconfig.GoRootNotFoundError, golangconfig.GoPathNotFoundError) as e: error_message = ''' Golang Build %s. Would you like to view the configuration documentation? ''' prompt = error_message % str_cls(e) if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', { 'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md' }) return (None, None)
def prepare(view, tool): return golangconfig.subprocess_info(tool, ['GOPATH', 'PATH'], view=view)
def do_test(): golangconfig.subprocess_info(executable_name, required_vars, optional_vars=optional_vars, view=mock_context.view, window=mock_context.window)
def guru(self, end_offset, begin_offset=None, mode="describe", callback=None): """ Builds the guru shell command and calls it, returning it's output as a string. """ pos = "#" + str(end_offset) if begin_offset is not None: pos = "#%i,#%i" % (begin_offset, end_offset) # golang config or shellenv ? cmd_env = '' if get_setting("goguru_use_golangconfig", False): try: toolpath, cmd_env = golangconfig.subprocess_info('guru', ['GOPATH', 'PATH'], view=self.view) toolpath = os.path.realpath(toolpath) except: error("golangconfig:", sys.exc_info()) return else: toolpath = 'guru' cmd_env = shellenv.get_env(for_subprocess=True)[1] debug("cmd_env", cmd_env) goguru_env = get_setting("goguru_env", {}) debug("goguru_env", goguru_env) cmd_env.update(goguru_env) debug("final_env", cmd_env) self.env = cmd_env guru_scope = ",".join(get_setting("goguru_scope", "")) # add local package to guru scope useCurrentPackage = get_setting("goguru_use_current_package", True) debug("goguru_use_current_package", useCurrentPackage) file_path = self.view.file_name() if useCurrentPackage: GOPATH = os.path.realpath(cmd_env["GOPATH"]) debug("GOPATH", GOPATH) local_package = get_local_package(GOPATH, file_path) debug("local_package", local_package) if sublime.platform() == 'windows': local_package = local_package.replace('\\', '/') self.local_package = local_package guru_scope = guru_scope + ',' + local_package guru_scope = guru_scope.strip() debug("guru_scope", guru_scope) if len(guru_scope) > 0: guru_scope = "-scope " + guru_scope guru_tags = "-tags \"" + " ".join(get_setting("goguru_tags", "")) + "\"" guru_json = "" if get_setting("goguru_json", False): guru_json = "-json" # Build guru cmd. cmd = "%(toolpath)s %(scope)s %(tags)s %(guru_json)s %(mode)s %(file_path)s:%(pos)s" % { "toolpath": toolpath, "file_path": file_path, "pos": pos, "guru_json": guru_json, "mode": mode, "scope": guru_scope, "tags": guru_tags, } debug("cmd", cmd) sublime.set_timeout_async(lambda: self.runInThread(cmd, callback, cmd_env), 0)
def _get_config(executable_name, required_vars, optional_vars=None, view=None, window=None): """ :param executable_name: A unicode string of the executable to locate, e.g. "go" or "gofmt" :param required_vars: A list of unicode strings of the environment variables that are required, e.g. "GOPATH". Obtains values from setting_value(). :param optional_vars: A list of unicode strings of the environment variables that are optional, but should be pulled from setting_value() if available - e.g. "GOOS", "GOARCH". Obtains values from setting_value(). :param view: A sublime.View object to use in finding project-specific settings. This should be passed whenever available. :param window: A sublime.Window object to use in finding project-specific settings. This will only work for Sublime Text 3, and should only be passed if no sublime.View object is available to pass via the view parameter. :return: A two-element tuple. If there was an error finding the executable or required vars: - [0] None - [1] None Otherwise: - [0] A string of the path to the executable - [1] A dict of environment variables for the executable """ try: return golangconfig.subprocess_info( executable_name, required_vars, optional_vars, view=view, window=window ) except (golangconfig.ExecutableError) as e: error_message = ''' Golang Build The %s executable could not be found. Please ensure it is installed and available via your PATH. Would you like to view documentation for setting a custom PATH? ''' prompt = error_message % e.name if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', {'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md'} ) except (golangconfig.EnvVarError) as e: error_message = ''' Golang Build The setting%s %s could not be found in your Sublime Text settings or your shell environment. Would you like to view the configuration documentation? ''' plural = 's' if len(e.missing) > 1 else '' setting_names = ', '.join(e.missing) prompt = error_message % (plural, setting_names) if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', {'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md'} ) except (golangconfig.GoRootNotFoundError, golangconfig.GoPathNotFoundError) as e: error_message = ''' Golang Build %s. Would you like to view the configuration documentation? ''' prompt = error_message % str_cls(e) if sublime.ok_cancel_dialog(_format_message(prompt), 'Open Documentation'): window.run_command( 'open_url', {'url': 'https://github.com/golang/sublime-build/blob/master/docs/configuration.md'} ) return (None, None)