def docutils_installed(self, object, result, data): global can_preview_rst global publish_string try: from docutils.core import publish_string except ImportError: Ide.warning("Failed to load docutils.core module") return can_preview_rst = True self.withdraw_notification('org.gnome.builder.html-preview.docutils')
def sphinx_installed(self, object, result, data): global can_preview_sphinx global sphinx try: import sphinx except ImportError: Ide.warning("Failed to load sphinx module") return can_preview_sphinx = True self.withdraw_notification('org.gnome.builder.html-preview.docutils') self.withdraw_notification('org.gnome.builder.html-preview.sphinx')
def do_load(self, pipeline): context = self.get_context() build_system = context.get_build_system() # Ignore pipeline unless this is a npm/nodejs project if type(build_system) != NPMBuildSystem: return package_json = build_system.props.project_file config = pipeline.get_configuration() system_type = config.get_device().get_system_type() builddir = pipeline.get_builddir() runtime = config.get_runtime() npm = 'npm' if config.getenv('NPM'): npm = config.getenv('NPM') elif not runtime.contains_program_in_path('npm'): raise OSError('The runtime must contain nodejs/npm to build npm modules') # Fetch dependencies so that we no longer need network access fetch_launcher = pipeline.create_launcher() fetch_launcher.set_name(_("Downloading npm dependencies")) fetch_launcher.set_cwd(package_json.get_parent().get_path()) fetch_launcher.push_argv(npm) if Ide.get_system_type() != system_type: fetch_launcher.push_argv('--arch') fetch_launcher.push_argv(system_type) fetch_launcher.push_argv('install') self.track(pipeline.connect_launcher(Ide.BuildPhase.DOWNLOADS, 0, fetch_launcher))
def do_load(self, view): self.context = Ide.widget_get_context(view) self.view = view self.can_preview = False self.sphinx_basedir = None self.sphinx_builddir = None group = view.get_action_group('editor-page') self.action = Gio.SimpleAction(name='preview-as-html', enabled=True) self.activate_handler = self.action.connect('activate', self.preview_activated) group.add_action(self.action) document = view.get_buffer() language = document.get_language() language_id = language.get_id() if language else None self.do_language_changed(language_id) # Add a shortcut for activation inside the editor controller = Dazzle.ShortcutController.find(view) controller.add_command_action('org.gnome.builder.html-preview.preview', '<Control><Alt>p', Dazzle.ShortcutPhase.CAPTURE, 'editor-page.preview-as-html')
def do_load(self, workspace): self.workspace = workspace self.workbench = Ide.widget_get_workbench(workspace) self.context = self.workbench.get_context() action = Gio.SimpleAction.new('find-other-file', None) action.connect('activate', self.on_activate) self.workspace.add_action(action)
def do_load(self, pipeline): context = self.get_context() build_system = context.get_build_system() # Ignore pipeline unless this is a cargo project if type(build_system) != CargoBuildSystem: return cargo_toml = build_system.props.project_file.get_path() config = pipeline.get_configuration() system_type = config.get_device().get_system_type() builddir = pipeline.get_builddir() runtime = config.get_runtime() # We might need to use cargo from ~/.cargo/bin cargo = locate_cargo_from_config(config) # Fetch dependencies so that we no longer need network access fetch_launcher = pipeline.create_launcher() fetch_launcher.setenv('CARGO_TARGET_DIR', builddir, True) fetch_launcher.push_argv(cargo) fetch_launcher.push_argv('fetch') fetch_launcher.push_argv('--manifest-path') fetch_launcher.push_argv(cargo_toml) self.track(pipeline.connect_launcher(Ide.BuildPhase.DOWNLOADS, 0, fetch_launcher)) # Fetch dependencies so that we no longer need network access build_launcher = pipeline.create_launcher() build_launcher.setenv('CARGO_TARGET_DIR', builddir, True) build_launcher.push_argv(cargo) build_launcher.push_argv('build') build_launcher.push_argv('--verbose') build_launcher.push_argv('--manifest-path') build_launcher.push_argv(cargo_toml) build_launcher.push_argv('--message-format') build_launcher.push_argv('human') if Ide.get_system_type() != system_type: build_launcher.push_argv('--target') build_launcher.push_argv(system_type) if config.props.parallelism > 0: build_launcher.push_argv('-j{}'.format(config.props.parallelism)) if not config.props.debug: build_launcher.push_argv('--release') clean_launcher = pipeline.create_launcher() clean_launcher.setenv('CARGO_TARGET_DIR', builddir, True) clean_launcher.push_argv(cargo) clean_launcher.push_argv('clean') clean_launcher.push_argv('--manifest-path') clean_launcher.push_argv(cargo_toml) build_stage = Ide.BuildStageLauncher.new(context, build_launcher) build_stage.set_name(_("Building project")) build_stage.set_clean_launcher(clean_launcher) self.track(pipeline.connect(Ide.BuildPhase.BUILD, 0, build_stage))
def do_parent_set(self, parent): """ After the context has been loaded, we want to watch the project Cargo.toml for changes if we find one. That will allow us to restart the process as necessary to pick up changes. """ if parent is None: return context = self.get_context() workdir = context.ref_workdir() cargo_toml = workdir.get_child('Cargo.toml') if cargo_toml.query_exists(): try: self._monitor = cargo_toml.monitor(0, None) self._monitor.set_rate_limit(5 * 1000) # 5 Seconds self._monitor.connect('changed', self._monitor_changed_cb) except Exception as ex: Ide.debug('Failed to monitor Cargo.toml for changes:', repr(ex))
def on_decide_policy_cb(self, webview, decision, decision_type): """Handle policy decisions from webview""" if decision_type == WebKit2.PolicyDecisionType.NAVIGATION_ACTION: # Don't allow navigating away from the current page action = decision.get_navigation_action() request = action.get_request() uri = request.get_uri() # print(">>> URI = ", uri) if uri != self.document.get_file().get_uri() \ and 'gnome-builder-sphinx' not in uri: toplevel = self.webview.get_toplevel() Ide.gtk_show_uri_on_window(toplevel, uri, GLib.get_monotonic_time()) decision.ignore() return True return False
def on_enumerator_loaded(self, parent, result, data): try: enumerator = parent.enumerate_children_finish(result) info = enumerator.next_file(None) while info is not None: name = info.get_name() gfile = parent.get_child(name) if info.get_file_type() == Gio.FileType.DIRECTORY: gfile.enumerate_children_async(_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_LOW, None, self.on_enumerator_loaded, None) else: # TODO: Ask java through introspection for classes with # TestCase and its public void methods or Annotation @Test # methods result, contents, etag = gfile.load_contents() tests = [x for x in str(contents).split('\\n') if 'public void' in x] tests = [v.replace("()", "").replace("public void","").strip() for v in tests] classname=name.replace(".java", "") for testname in tests: # http://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html # it has to be junit 4.x command = ["mvn", "-Dtest={}#{}".format(classname, testname), "test"] test = MavenTest(group=classname, id=classname+testname, display_name=testname) test.set_command(command) self.add(test) info = enumerator.next_file(None) enumerator.close() except Exception as ex: Ide.warning(repr(ex))
def on_enumerator_loaded(self, parent, result, basename): try: files = Gio.ListStore.new(Ide.SearchResult) enumerator = parent.enumerate_children_finish(result) info = enumerator.next_file(None) if '.' in basename: prefix = basename[:basename.rindex('.')+1] else: prefix = basename while info is not None: name = info.get_name() if name != basename and name.startswith(prefix): content_type = info.get_attribute_string(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) display_name = info.get_attribute_string(Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME) icon = info.get_attribute_object(Gio.FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON) icon_name = icon.to_string() if icon else None gfile = parent.get_child(name) ifile = Ide.File.new(self.context, gfile) result = OtherFileSearchResult(file=ifile, icon_name=icon_name, title=display_name) files.append(result) info = enumerator.next_file(None) enumerator.close() count = files.get_n_items() if count == 1: file = files.get_item(0).file.get_file() self.workbench.open_files_async([file], 'editor', 0, None, None) elif count: self.present_results(files, basename) except Exception as ex: Ide.warning(repr(ex)) return
def do_locate(self, path): if path.startswith('license.'): filename = GLib.basename(path) manager = GtkSource.LanguageManager.get_default() language = manager.guess_language(filename, None) if self.license is None or language is None: return self.empty() header = Ide.language_format_header(language, self.license) gbytes = GLib.Bytes(header.encode()) return Gio.MemoryInputStream.new_from_bytes(gbytes) return super().do_locate(self, path)
def _ensure_started(self): """ Start the Vala service which provides communication with the Vala Language Server. We supervise our own instance of the language server and restart it as necessary using the Ide.SubprocessSupervisor. Various extension points (diagnostics, symbol providers, etc) use the GVlsService to access the rust components they need. """ # To avoid starting the `gvls` process unconditionally at startup, # we lazily start it when the first provider tries to bind a client # to its :client property. if not self._has_started: self._has_started = True # Setup a launcher to spawn the rust language server launcher = self._create_launcher() launcher.set_clear_env(False) # Locate the directory of the project and run gvls from there. workdir = self.get_context().ref_workdir() launcher.set_cwd(workdir.get_path()) # If org.gnome.gvls.stdio.Server is installed by GVls path = 'org.gnome.gvls.stdio.Server' # Setup our Argv. We want to communicate over STDIN/STDOUT, # so it does not require any command line options. launcher.push_argv(path) # Spawn our peer process and monitor it for # crashes. We may need to restart it occasionally. self._supervisor = Ide.SubprocessSupervisor() self._supervisor.connect('spawned', self._gvls_spawned) self._supervisor.set_launcher(launcher) self._supervisor.start()
def do_init_async(self, io_priority, cancellable, callback, data): task = Gio.Task.new(self, cancellable, callback) # This is all done synchronously, doing it in a thread would probably # be somewhat ideal although unnecessary at this time. try: # Maybe this is a package.json if self.props.project_file.get_basename() in ('package.json', ): task.return_boolean(True) return # Maybe this is a directory with a package.json if self.props.project_file.query_file_type( 0) == Gio.FileType.DIRECTORY: child = self.props.project_file.get_child('package.json') if child.query_exists(None): self.props.project_file = child task.return_boolean(True) return except Exception as ex: task.return_error(ex) task.return_error(Ide.NotSupportedError())
def do_populate(self, search_context, search_terms, max_results, cancellable): result = Ide.SearchResult(Context, 'weeee', 'more weeeeeee', 0.5) search_context.add_result(self, result) search_context.provider_completed(self)
def install_docutils(self): transfer = Ide.PkconTransfer(packages=['python3-docutils']) manager = Gio.Application.get_default().get_transfer_manager() manager.execute_async(transfer, None, self.docutils_installed, None)
def install_sphinx(self): transfer = Ide.PkconTransfer(packages=['python3-sphinx']) context = self.workbench.get_context() manager = context.get_transfer_manager() manager.execute_async(transfer, None, self.sphinx_installed, None)
def do_activate(self, last_focus): workspace = Ide.widget_get_workspace(last_focus) editor = workspace.get_surface_by_name('editor') loc = Ide.Location.new(self.file, -1, -1) editor.focus_location(loc)
def do_diagnose_finish(self, result): if result.propagate_boolean(): diagnostics = Ide.Diagnostics() for diag in result.diagnostics_list: diagnostics.add(diag) return diagnostics
def install_docutils(self): transfer = Ide.PkconTransfer(packages=['python3-docutils']) context = self.workbench.get_context() manager = context.get_transfer_manager() manager.execute_async(transfer, None, self.docutils_installed, None)
def _on_pipeline_diagnostic(self, obj, diagnostic): try: self.source_file = diagnostic.get_file() except BaseException as exc: Ide.debug('On Pipeline Loaded start get build flags error: {}'.format(exc.args))
def create_configuration_variant(self): try: b = GLib.VariantBuilder(GLib.VariantType.new('a{sv}')) b.add_value( self.create_dict_entry_boolean('initialized', self.initialized)) b.add_value( self.create_dict_entry_boolean('defaultNamespaces', self.default_namespaces)) b.add_value( self.create_dict_entry_boolean('defaultVapiDirs', self.default_vapi_dirs)) b.add_value( self.create_dict_entry_boolean('scanWorkspace', self.scan_work_space)) b.add_value( self.create_dict_entry_boolean('addUsingNamespaces', self.add_using_namespaces)) b.add_value( self.create_dict_entry_boolean('mesonBuildSystem', self.meson_build_system)) b.add_value( self.create_dict_entry_string('libraryVapi', self.library_vapidir)) Ide.debug('Library VAPI dir:{0}'.format(self.library_vapidir)) b.add_value( self.create_dict_entry_string('systemVapi', self.system_vapidir)) Ide.debug('System VAPI dir:{0}'.format(self.system_vapidir)) b.add_value( self.create_dict_entry_string('valaApiVersion', self.vala_api_version)) b.add_value( self.create_dict_entry_string('mesonCompileCommands', self.meson_compile_commands)) b.add_value( self.create_dict_entry_string('mesonTargetsIntro', self.meson_targets_intro)) ad = GLib.Variant.new_string('valaArgs') vadi = self.dict_to_array_variant(self.vala_args) adi = GLib.Variant.new_dict_entry(ad, GLib.Variant.new_variant(vadi)) b.add_value(adi) od = GLib.Variant.new_string('options') vodi = self.list_to_variant(self.options) odi = GLib.Variant.new_dict_entry(od, GLib.Variant.new_variant(vodi)) b.add_value(odi) pd = GLib.Variant.new_string('packages') vpdi = self.list_to_variant(self.packages) pdi = GLib.Variant.new_dict_entry(pd, GLib.Variant.new_variant(vpdi)) b.add_value(pdi) fd = GLib.Variant.new_string('files') vfdi = self.list_to_variant(self.files) fdi = GLib.Variant.new_dict_entry(fd, GLib.Variant.new_variant(vfdi)) b.add_value(fdi) return GLib.Variant.new_variant(b.end()) except Error as e: Ide.debug('On Load Configuration Error: {}'.format(e.message)) return GLib.Variant('a{sv}', {})
def _did_change_configuration(self, source_object, result, user_data): try: self._client.send_notification_finish(result) except BaseException as exc: Ide.debug('Change Configuration Notification error: {}'.format(exc.args))
def _parse_build_commands(self): try: self.build_args = [] ctx = self._client.ref_context() buildmgr = Ide.BuildManager.from_context (ctx) self.pipeline = buildmgr.get_pipeline () if self.pipeline != None: if self.pipeline.has_configured(): bcdir = Gio.File.new_for_path(self.pipeline.get_builddir()) if self.meson_build_system: bcf = Gio.File.new_for_uri(bcdir.get_uri()+'/compile_commands.json') if not bcf.query_exists(None): return self.read_meson_compile_commands(bcf) if self.build_monitor == None: self.build_monitor = bcf.monitor(Gio.FileMonitorFlags.NONE, None) self.build_monitor.connect('changed', self._build_config_changed) cc = Ide.CompileCommands.new() cc.load (bcf) commands = cc.lookup (self.source_file, '') if commands != None: self.build_args = commands[0] self.files = [] self.packages = [] self.vala_args = {} self.options = [] found_package = False found_arg = False arg_name = '' for s in self.build_args: if found_package: self.packages += [s] found_package = False continue if found_arg: self.vala_args[arg_name] = s found_arg = False continue if s == '--pkg' or s == 'pkg': found_package = True if s.startswith('-') and not (s == '--pkg' or s == 'pkg'): if s.startswith('--version'): continue if s.startswith('--api-version'): continue if s == '-C' or s == '--ccode': self.vala_args[s] = '' continue if s == '--use-header': self.vala_args[s] = '' continue if s == '--fast-vapi': self.vala_args[s] = '' continue if s == '--use-fast-vapi': self.vala_args[s] = '' continue if s == '--vapi-comments': self.vala_args[s] = '' continue if s == '--deps': self.vala_args[s] = '' continue if s == '-c' or s == '--compile': self.vala_args[s] = '' continue if s == '-g' or s == '--debug': self.vala_args[s] = '' continue if s == '--enable-mem-profiler': self.vala_args[s] = '' continue if s == '--nostdpkg': self.vala_args[s] = '' continue if s == '--disable-assert': self.vala_args[s] = '' continue if s == '--enable-checking': self.vala_args[s] = '' continue if s == '--enable-deprecated': self.vala_args[s] = '' continue if s == '--hide-internal': self.vala_args[s] = '' continue if s == '--enable-experimental': self.vala_args[s] = '' continue if s == '--disable-warnings': self.vala_args[s] = '' continue if s == '--fatal-warnings': self.vala_args[s] = '' continue if s == '--disable-since-check': self.vala_args[s] = '' continue if s == '--enable-experimental-non-null': self.vala_args[s] = '' continue if s == '--enable-gobject-tracing': self.vala_args[s] = '' continue if s == '--save-temps': self.vala_args[s] = '' continue if s == '-q' or s == '--quiet': self.vala_args[s] = '' continue if s == '-v' or s == '--verbose': self.vala_args[s] = '' continue if s == '--no-color': self.vala_args[s] = '' continue if s == '--enable-version-header': self.vala_args[s] = '' continue if s == '--disable-version-header': self.vala_args[s] = '' continue if s == '--run-args': self.vala_args[s] = '' continue if s == '--abi-stability': self.vala_args[s] = '' continue if '=' in s: ps = s.split('=') if len(ps) == 2: self.vala_args[ps[0]] = ps[1] continue found_arg = True arg_name = s continue except BaseException as exc: Ide.debug('Parse Build Commands Error: {}'.format(exc.args))
# # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # import gi import threading import os import json from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject from gi.repository import Ide Ide.g_file_add_ignored_pattern('node_modules') _ = Ide.gettext class NPMBuildSystemDiscovery(Ide.SimpleBuildSystemDiscovery): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.props.glob = 'package.json' self.props.hint = 'npm_plugin' self.props.priority = 100 class NPMBuildSystem(Ide.Object, Ide.BuildSystem): project_file = GObject.Property(type=Gio.File)
def build_flags_thread(): try: with open(commands_file) as f: commands = json.loads(f.read(), encoding='utf-8') except (json.JSONDecodeError, FileNotFoundError, UnicodeDecodeError) as e: task.return_error( GLib.Error('Failed to decode meson json: {}'.format(e))) return infile = task.ifile.get_path() # If this is a header file we want the flags for a C/C++/Objc file. # (Extensions Match GtkSourceViews list) is_header = infile.endswith(('.h', '.hpp', '.hh', '.h++', '.hp')) if is_header: # So just try to find a compilable file with the same prefix as # that is *probably* correct. infile = infile.rpartition('.')[0] + '.' for c in commands: filepath = path.normpath(path.join(c['directory'], c['file'])) if (is_header is False and filepath == infile) or \ (is_header is True and filepath.startswith(infile)): try: task.build_flags = extract_flags( c['command'], builddir) except GLib.Error as e: task.return_error(e) return break if infile.endswith('.vala'): # We didn't find anything in the compile_commands.json, so now try to use # the compdb from ninja and see if it has anything useful for us. ninja = None for name in _NINJA_NAMES: if runtime.contains_program_in_path(name): ninja = name break if ninja: ret = execInRuntime(runtime, ninja, '-t', 'compdb', 'vala_COMPILER', directory=builddir) try: commands = json.loads(ret, encoding='utf-8') except Exception as e: task.return_error( GLib.Error( 'Failed to decode ninja json: {}'.format(e))) return for c in commands: try: _, argv = GLib.shell_parse_argv(c['command']) # TODO: It would be nice to filter these arguments a bit, # but the vala plugin should handle that fine. task.build_flags = argv task.return_boolean(True) return except: pass Ide.debug('No flags found for file', infile) task.return_boolean(True)
def install_sphinx(self): transfer = Ide.PkconTransfer(packages=['python3-sphinx']) manager = Gio.Application.get_default().get_transfer_manager() manager.execute_async(transfer, None, self.sphinx_installed, None)
# along with this program. If not, see <http://www.gnu.org/licenses/>. # import gi import threading import os import json gi.require_version('Ide', '1.0') from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject from gi.repository import Ide Ide.vcs_register_ignored('node_modules') class NPMBuildSystem(Ide.Object, Ide.BuildSystem, Gio.AsyncInitable): project_file = GObject.Property(type=Gio.File) def do_get_id(self): return 'npm' def do_get_display_name(self): return 'NPM (node.js)' def do_init_async(self, io_priority, cancellable, callback, data): task = Gio.Task.new(self, cancellable, callback) # This is all done synchronously, doing it in a thread would probably # be somewhat ideal although unnecessary at this time.
def do_populate(self, context): self.current_word = Ide.CompletionProvider.context_current_word( context) self.current_word_lower = self.current_word.lower() _, iter = context.get_iter() begin = iter.copy() begin.set_line_offset(0) line_str = begin.get_slice(iter) # If we have no results yet, but a thread is active and mostly matches # our line prefix, then we should just let that one continue but tell # it to deliver to our new context. if self.context is not None: if not line_str.startswith(self.line_str): self.cancellable.cancel() self.context = context if iter.get_line() == self.line and not self.invalidates(line_str): if self.results and self.results.replay(self.current_word): self.results.present(self, context) return self.line_str = line_str buffer = iter.get_buffer() begin, end = buffer.get_bounds() filename = (iter.get_buffer().get_file().get_file().get_path()) text = buffer.get_text(begin, end, True) line = iter.get_line() + 1 column = iter.get_line_offset() self.line = iter.get_line() self.line_offset = iter.get_line_offset() results = Ide.CompletionResults(query=self.current_word) self.cancellable = cancellable = Gio.Cancellable() context.connect('cancelled', lambda *_: cancellable.cancel()) def async_handler(proxy, result, user_data): (self, results, context) = user_data try: variant = proxy.call_finish(result) # unwrap outer tuple variant = variant.get_child_value(0) for i in range(variant.n_children()): proposal = JediCompletionProposal(self, context, variant, i) results.take_proposal(proposal) self.complete(context, results) except Exception as ex: if isinstance(ex, GLib.Error) and \ ex.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED): return print(repr(ex)) context.add_proposals(self, [], True) self.proxy.call( 'CodeComplete', GLib.Variant('(siis)', (filename, self.line, self.line_offset, text)), 0, 10000, cancellable, async_handler, (self, results, context))
def do_load(self, pipeline): context = self.get_context() build_system = context.get_build_system() # Ignore pipeline unless this is a cargo project if type(build_system) != CargoBuildSystem: return cargo_toml = build_system.props.project_file.get_path() config = pipeline.get_configuration() system_type = config.get_device().get_system_type() builddir = pipeline.get_builddir() runtime = config.get_runtime() # We might need to use cargo from ~/.cargo/bin cargo = _CARGO if config.getenv('CARGO'): cargo = config.getenv('CARGO') elif not runtime.contains_program_in_path(_CARGO): cargo_in_home = os.path.expanduser('~/.cargo/bin/cargo') if os.path.exists(cargo_in_home): cargo = cargo_in_home # Fetch dependencies so that we no longer need network access fetch_launcher = pipeline.create_launcher() fetch_launcher.setenv('CARGO_TARGET_DIR', builddir, True) fetch_launcher.push_argv(cargo) fetch_launcher.push_argv('fetch') fetch_launcher.push_argv('--manifest-path') fetch_launcher.push_argv(cargo_toml) self.track( pipeline.connect_launcher(Ide.BuildPhase.DOWNLOADS, 0, fetch_launcher)) # Fetch dependencies so that we no longer need network access build_launcher = pipeline.create_launcher() build_launcher.setenv('CARGO_TARGET_DIR', builddir, True) build_launcher.push_argv(cargo) build_launcher.push_argv('build') build_launcher.push_argv('--verbose') build_launcher.push_argv('--manifest-path') build_launcher.push_argv(cargo_toml) build_launcher.push_argv('--message-format') build_launcher.push_argv('human') if Ide.get_system_type() != system_type: build_launcher.push_argv('--target') build_launcher.push_argv(system_type) if config.props.parallelism > 0: build_launcher.push_argv('-j{}'.format(config.props.parallelism)) if not config.props.debug: build_launcher.push_argv('--release') clean_launcher = pipeline.create_launcher() clean_launcher.setenv('CARGO_TARGET_DIR', builddir, True) clean_launcher.push_argv(cargo) clean_launcher.push_argv('clean') clean_launcher.push_argv('--manifest-path') clean_launcher.push_argv(cargo_toml) build_stage = Ide.BuildStageLauncher.new(context, build_launcher) build_stage.set_clean_launcher(clean_launcher) self.track(pipeline.connect(Ide.BuildPhase.BUILD, 0, build_stage))