def test_tmp_filename_gives_good_file(self): first = utils.tmp_filename('test') second = utils.tmp_filename('test') self.assertFalse(core.exists(first)) self.assertFalse(core.exists(second)) self.assertNotEqual(first, second) self.assertTrue(os.path.basename(first).startswith('git-cola-test')) self.assertTrue(os.path.basename(second).startswith('git-cola-test'))
def clone_repo(spawn=True): """ Present GUI controls for cloning a repository A new cola session is invoked when 'spawn' is True. """ url, ok = qtutils.prompt(N_('Path or URL to clone (Env. $VARS okay)')) url = os.path.expandvars(url) if not ok or not url: return None try: # Pick a suitable basename by parsing the URL newurl = url.replace('\\', '/').rstrip('/') default = newurl.rsplit('/', 1)[-1] if default == '.git': # The end of the URL is /.git, so assume it's a file path default = os.path.basename(os.path.dirname(newurl)) if default.endswith('.git'): # The URL points to a bare repo default = default[:-4] if url == '.': # The URL is the current repo default = os.path.basename(core.getcwd()) if not default: raise except: Interaction.information( N_('Error Cloning'), N_('Could not parse Git URL: "%s"') % url) Interaction.log(N_('Could not parse Git URL: "%s"') % url) return None # Prompt the user for a directory to use as the parent directory msg = N_('Select a parent directory for the new clone') dirname = qtutils.opendir_dialog(msg, main.model().getcwd()) if not dirname: return None count = 1 destdir = os.path.join(dirname, default) olddestdir = destdir if core.exists(destdir): # An existing path can be specified msg = (N_('"%s" already exists, cola will create a new directory') % destdir) Interaction.information('Directory Exists', msg) # Make sure the new destdir doesn't exist while core.exists(destdir): destdir = olddestdir + str(count) count += 1 if cmds.do(cmds.Clone, url, destdir, spawn=spawn): return destdir return None
def do(self): if not self.filenames: return filename = self.filenames[0] if not core.exists(filename): return editor = prefs.editor() opts = [] if self.line_number is None: opts = self.filenames else: # Single-file w/ line-numbers (likely from grep) editor_opts = { "*vim*": ["+" + self.line_number, filename], "*emacs*": ["+" + self.line_number, filename], "*textpad*": ["%s(%s,0)" % (filename, self.line_number)], "*notepad++*": ["-n" + self.line_number, filename], } opts = self.filenames for pattern, opt in editor_opts.items(): if fnmatch(editor, pattern): opts = opt break try: core.fork(utils.shell_split(editor) + opts) except Exception as e: message = N_('Cannot exec "%s": please configure your editor') % editor details = core.decode(e.strerror) Interaction.critical(N_("Error Editing File"), message, details)
def do(self): if not self.filenames: return filename = self.filenames[0] if not core.exists(filename): return editor = prefs.editor() opts = [] if self.line_number is None: opts = self.filenames else: # Single-file w/ line-numbers (likely from grep) editor_opts = { '*vim*': ['+' + self.line_number, filename], '*emacs*': ['+' + self.line_number, filename], '*textpad*': ['%s(%s,0)' % (filename, self.line_number)], '*notepad++*': ['-n' + self.line_number, filename], } opts = self.filenames for pattern, opt in editor_opts.items(): if fnmatch(editor, pattern): opts = opt break try: core.fork(utils.shell_split(editor) + opts) except Exception as e: message = (N_('Cannot exec "%s": please configure your editor') % editor) Interaction.critical(N_('Error Editing File'), message, ustr(e))
def asdict(self): path = self.path() if core.exists(path): return read_json(path) # We couldn't find ~/.config/git-cola, try ~/.cola values = {} path = os.path.join(core.expanduser('~'), '.cola') if core.exists(path): json_values = read_json(path) # Keep only the entries we care about for key in self.values: try: values[key] = json_values[key] except KeyError: pass return values
def test_tmp_filename_gives_good_file(): try: first = utils.tmp_filename('test') assert core.exists(first) assert os.path.basename(first).startswith('git-cola-test') finally: os.remove(first) try: second = utils.tmp_filename('test') assert core.exists(second) assert os.path.basename(second).startswith('git-cola-test') finally: os.remove(second) assert first != second
def file_icon(filename): """ Returns the full path to an icon file corresponding to filename"s contents. """ exists = core.exists(filename) return (resources.icon(ident_file_type(filename, exists)), exists)
def stage_paths(self, paths): """Stages add/removals to git.""" if not paths: self.stage_all() return add = [] remove = [] for path in set(paths): if core.exists(path): add.append(path) else: remove.append(path) self.notify_observers(self.message_about_to_update) # `git add -u` doesn't work on untracked files if add: self._sliced_add(add) # If a path doesn't exist then that means it should be removed # from the index. We use `git add -u` for that. if remove: while remove: self.git.add('--', u=True, *remove[:42]) remove = remove[42:] self._update_files() self.notify_observers(self.message_updated)
def merge_message_path(): """Return the path to .git/MERGE_MSG or .git/SQUASH_MSG.""" for basename in ("MERGE_MSG", "SQUASH_MSG"): path = git.git_path(basename) if core.exists(path): return path return None
def _create_staged_context_menu(self, menu, s): if s.staged[0] in self.m.submodules: return self._create_staged_submodule_context_menu(menu, s) if self.m.unstageable(): action = menu.addAction(icons.remove(), N_("Unstage Selected"), cmds.run(cmds.Unstage, self.staged())) action.setShortcut(hotkeys.STAGE_SELECTION) # Do all of the selected items exist? all_exist = all(not i in self.m.staged_deleted and core.exists(i) for i in self.staged()) if all_exist: menu.addAction(self.launch_editor_action) menu.addAction(self.launch_difftool_action) if all_exist and not utils.is_win32(): menu.addSeparator() open_default = cmds.run(cmds.OpenDefaultApp, self.staged()) action = menu.addAction(icons.default_app(), cmds.OpenDefaultApp.name(), open_default) action.setShortcut(hotkeys.PRIMARY_ACTION) action = menu.addAction(icons.folder(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(hotkeys.SECONDARY_ACTION) if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) menu.addAction(self.view_history_action) menu.addAction(self.view_blame_action) return menu
def _create_staged_context_menu(self, menu, s): if s.staged[0] in self.m.submodules: return self._create_staged_submodule_context_menu(menu, s) if self.m.unstageable(): action = menu.addAction( qtutils.remove_icon(), N_("Unstage Selected"), cmds.run(cmds.Unstage, self.staged()) ) action.setShortcut(cmds.Unstage.SHORTCUT) # Do all of the selected items exist? all_exist = all(not i in self.m.staged_deleted and core.exists(i) for i in self.staged()) if all_exist: menu.addAction(self.launch_editor_action) menu.addAction(self.launch_difftool_action) if all_exist and not utils.is_win32(): menu.addSeparator() action = menu.addAction( qtutils.file_icon(), cmds.OpenDefaultApp.name(), cmds.run(cmds.OpenDefaultApp, self.staged()) ) action.setShortcut(cmds.OpenDefaultApp.SHORTCUT) action = menu.addAction(qtutils.open_file_icon(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(cmds.OpenParentDir.SHORTCUT) if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) return menu
def do(self): if not self.filenames: return filename = self.filenames[0] if not core.exists(filename): return editor = prefs.editor() opts = [] if self.line_number is None: opts = self.filenames else: # Single-file w/ line-numbers (likely from grep) editor_opts = { '*vim*': ['+'+self.line_number, filename], '*emacs*': ['+'+self.line_number, filename], '*textpad*': ['%s(%s,0)' % (filename, self.line_number)], '*notepad++*': ['-n'+self.line_number, filename], } opts = self.filenames for pattern, opt in editor_opts.items(): if fnmatch(editor, pattern): opts = opt break try: core.fork(utils.shell_split(editor) + opts) except Exception as e: message = (N_('Cannot exec "%s": please configure your editor') % editor) Interaction.critical(N_('Error Editing File'), message, str(e))
def html_docs(): """Return the path to the cola html documentation.""" # index.html only exists after the install-docs target is run, # so fallback to git-cola.txt. htmldocs = doc('html', 'index.html') if core.exists(htmldocs): return htmldocs return doc('git-cola.txt')
def _load(self): path = self.path() if not core.exists(path): return self._load_dot_cola() try: fp = core.xopen(path, 'rt') return mkdict(json.load(fp)) except: # bad json return {}
def icon_name_for_file(filename, staged=False, untracked=False): """Returns a file path representing a corresponding file path.""" exists = True if staged: exists = core.exists(filename) if exists: icon_name = 'staged-item.png' else: icon_name = 'removed.png' elif untracked: icon_name = 'untracked.png' else: exists = core.exists(filename) if exists: icon_name = icon_name_for_filename(filename) else: icon_name = 'removed.png' return (icon_name, exists)
def _watch_directory(self, directory): """Set up a directory for monitoring by inotify""" if not self._wmgr: return directory = core.realpath(directory) if not core.exists(directory): return if directory not in self._dirs_seen: self._wmgr.add_watch(directory, self._mask) self._dirs_seen.add(directory)
def load(self): path = self.path() if core.exists(path): self.values.update(read_json(path)) try: os.unlink(path) except: pass return True return False
def html_docs(): """Return the path to the cola html documentation.""" # html/index.html only exists after the install-docs target is run. # Fallback to the source tree and lastly git-cola.rst. paths_to_try = (('html', 'index.html'), ('_build', 'html', 'index.html')) for paths in paths_to_try: docdir = doc(*paths) if core.exists(docdir): return docdir return doc('git-cola.rst')
def _create_unstaged_context_menu(self, menu, s): modified_submodule = (s.modified and s.modified[0] in self.m.submodules) if modified_submodule: return self._create_modified_submodule_context_menu(menu, s) if self.m.stageable(): action = menu.addAction(qtutils.add_icon(), N_('Stage Selected'), cmds.run(cmds.Stage, self.unstaged())) action.setShortcut(hotkeys.STAGE_SELECTION) # Do all of the selected items exist? all_exist = all(not i in self.m.unstaged_deleted and core.exists(i) for i in self.staged()) if all_exist and self.unstaged(): menu.addAction(self.launch_editor_action) if all_exist and s.modified and self.m.stageable(): menu.addAction(self.launch_difftool_action) if s.modified and self.m.stageable(): if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) if all_exist and self.unstaged() and not utils.is_win32(): menu.addSeparator() action = menu.addAction(qtutils.file_icon(), cmds.OpenDefaultApp.name(), cmds.run(cmds.OpenDefaultApp, self.unstaged())) action.setShortcut(hotkeys.PRIMARY_ACTION) action = menu.addAction(qtutils.open_file_icon(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(hotkeys.SECONDARY_ACTION) if all_exist and s.untracked: menu.addSeparator() if self.move_to_trash_action is not None: menu.addAction(self.move_to_trash_action) menu.addAction(self.delete_untracked_files_action) menu.addSeparator() menu.addAction(qtutils.theme_icon('edit-clear.svg'), N_('Add to .gitignore'), cmds.run(cmds.Ignore, map(lambda x: '/' + x, self.untracked()))) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) if not selection.selection_model().is_empty(): menu.addAction(self.view_history_action) return menu
def _create_unstaged_context_menu(self, menu, s): modified_submodule = (s.modified and s.modified[0] in self.m.submodules) if modified_submodule: return self._create_modified_submodule_context_menu(menu, s) if self.m.stageable(): action = menu.addAction(icons.add(), N_('Stage Selected'), cmds.run(cmds.Stage, self.unstaged())) action.setShortcut(hotkeys.STAGE_SELECTION) # Do all of the selected items exist? all_exist = all(i not in self.m.unstaged_deleted and core.exists(i) for i in self.staged()) if all_exist and self.unstaged(): menu.addAction(self.launch_editor_action) if all_exist and s.modified and self.m.stageable(): menu.addAction(self.launch_difftool_action) if s.modified and self.m.stageable(): if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) if all_exist and self.unstaged() and not utils.is_win32(): menu.addSeparator() open_default = cmds.run(cmds.OpenDefaultApp, self.unstaged()) action = menu.addAction(icons.default_app(), cmds.OpenDefaultApp.name(), open_default) action.setShortcut(hotkeys.PRIMARY_ACTION) action = menu.addAction(icons.folder(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(hotkeys.SECONDARY_ACTION) if all_exist and s.untracked: menu.addSeparator() if self.move_to_trash_action is not None: menu.addAction(self.move_to_trash_action) menu.addAction(self.delete_untracked_files_action) menu.addSeparator() menu.addAction(icons.edit(), N_('Add to .gitignore'), cmds.run(cmds.Ignore, [('/' + x) for x in self.untracked()])) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) if not selection.selection_model().is_empty(): menu.addAction(self.view_history_action) menu.addAction(self.view_blame_action) return menu
def terminal(self): term = self.get("cola.terminal", None) if not term: # find a suitable default terminal term = "xterm -e" # for mac osx candidates = ("xfce4-terminal", "konsole", "gnome-terminal") for basename in candidates: if core.exists("/usr/bin/%s" % basename): term = "%s -e" % basename break return term
def do(self): if not self.filenames: return new_additions = '\n'.join(self.filenames) + '\n' for_status = new_additions if core.exists('.gitignore'): current_list = core.read('.gitignore') new_additions = current_list.rstrip() + '\n' + new_additions core.write('.gitignore', new_additions) Interaction.log_status(0, 'Added to .gitignore:\n%s' % for_status, '') self.model.update_file_status()
def _install_custom_language(): """Allow a custom language to be set in ~/.config/git-cola/language""" lang_file = resources.config_home('language') if not core.exists(lang_file): return try: lang = core.read(lang_file).strip() except: return if lang: compat.setenv('LANGUAGE', lang)
def terminal(self): term = self.get('cola.terminal', None) if not term: # find a suitable default terminal term = 'xterm -e' # for mac osx candidates = ('xfce4-terminal', 'konsole', 'gnome-terminal') for basename in candidates: if core.exists('/usr/bin/%s' % basename): term = '%s -e' % basename break return term
def _create_unstaged_context_menu(self, menu, s): modified_submodule = (s.modified and s.modified[0] in self.m.submodules) if modified_submodule: return self._create_modified_submodule_context_menu(menu, s) if self.m.stageable(): action = menu.addAction(qtutils.icon('add.svg'), N_('Stage Selected'), cmds.run(cmds.Stage, self.unstaged())) action.setShortcut(cmds.Stage.SHORTCUT) # Do all of the selected items exist? all_exist = all(not i in self.m.unstaged_deleted and core.exists(i) for i in self.staged()) if all_exist and self.unstaged(): menu.addAction(self.launch_editor_action) if all_exist and s.modified and self.m.stageable(): menu.addAction(self.launch_difftool_action) if s.modified and self.m.stageable(): if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) menu.addAction(self.revert_uncommitted_edits_action) if all_exist and self.unstaged() and not utils.is_win32(): menu.addSeparator() action = menu.addAction(qtutils.file_icon(), cmds.OpenDefaultApp.name(), cmds.run(cmds.OpenDefaultApp, self.unstaged())) action.setShortcut(cmds.OpenDefaultApp.SHORTCUT) action = menu.addAction(qtutils.open_file_icon(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(cmds.OpenParentDir.SHORTCUT) if all_exist and s.untracked: menu.addSeparator() if self.move_to_trash_action is not None: menu.addAction(self.move_to_trash_action) menu.addAction(self.delete_untracked_files_action) menu.addSeparator() menu.addAction(qtutils.icon('edit-clear.svg'), N_('Add to .gitignore'), cmds.run(cmds.Ignore, map(lambda x: '/' + x, self.untracked()))) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) return menu
def do(self): if not self.filenames: return new_additions = "\n".join(self.filenames) + "\n" for_status = new_additions if core.exists(".gitignore"): current_list = core.read(".gitignore") new_additions = current_list.rstrip() + "\n" + new_additions core.write(".gitignore", new_additions) Interaction.log_status(0, "Added to .gitignore:\n%s" % for_status, "") self.model.update_file_status()
def diff_helper(commit=None, ref=None, endref=None, filename=None, cached=True, head=None, amending=False, with_diff_header=False, suppress_header=True, reverse=False, git=git): "Invokes git diff on a filepath." if commit: ref, endref = commit + '^', commit argv = [] if ref and endref: argv.append('%s..%s' % (ref, endref)) elif ref: for r in utils.shell_split(ref.strip()): argv.append(r) elif head and amending and cached: argv.append(head) encoding = None if filename: argv.append('--') if type(filename) is list: argv.extend(filename) else: argv.append(filename) cfg = gitcfg.current() encoding = cfg.file_encoding(filename) if filename is not None: deleted = cached and not core.exists(filename) else: deleted = False status, out, err = git.diff(R=reverse, M=True, cached=cached, _encoding=encoding, *argv, **common_diff_opts()) if status != 0: # git init if with_diff_header: return ('', '') else: return '' return extract_diff_header(status, deleted, with_diff_header, suppress_header, out)
def icon_file(filename, staged=False, untracked=False): """Returns a file path representing a corresponding file path.""" if staged: if core.exists(filename): ifile = resources.icon('staged-item.png') else: ifile = resources.icon('removed.png') elif untracked: ifile = resources.icon('untracked.png') else: ifile = utils.file_icon(filename) return ifile
def abort_merge(): """Abort a merge by reading the tree at HEAD.""" # Reset the worktree git.read_tree('HEAD', reset=True, u=True, v=True) # remove MERGE_HEAD merge_head = git.git_path('MERGE_HEAD') if core.exists(merge_head): core.unlink(merge_head) # remove MERGE_MESSAGE, etc. merge_msg_path = merge_message_path() while merge_msg_path: core.unlink(merge_msg_path) merge_msg_path = merge_message_path()
def do(self): new_additions = '' for fname in self.filenames: new_additions = new_additions + fname + '\n' for_status = new_additions if new_additions: if core.exists('.gitignore'): current_list = core.read('.gitignore') new_additions = new_additions + current_list core.write('.gitignore', new_additions) Interaction.log_status(0, 'Added to .gitignore:\n%s' % for_status, '') self.model.update_file_status()
def abort_merge(): """Abort a merge by reading the tree at HEAD.""" # Reset the worktree git.read_tree("HEAD", reset=True, u=True, v=True) # remove MERGE_HEAD merge_head = git.git_path("MERGE_HEAD") if core.exists(merge_head): core.unlink(merge_head) # remove MERGE_MESSAGE, etc. merge_msg_path = merge_message_path() while merge_msg_path: core.unlink(merge_msg_path) merge_msg_path = merge_message_path()
def do(self): new_additions = '' for fname in self.filenames: new_additions = new_additions + fname + '\n' for_status = new_additions if new_additions: if core.exists('.gitignore'): current_list = core.read('.gitignore') new_additions = new_additions + current_list core.write('.gitignore', new_additions) Interaction.log_status( 0, 'Added to .gitignore:\n%s' % for_status, '') self.model.update_file_status()
def save_archive(self): filename = self.filename if not filename: return if core.exists(filename): title = N_('Overwrite File?') msg = N_('The file "%s" exists and will be overwritten.') % filename info_txt = N_('Overwrite "%s"?') % filename ok_txt = N_('Overwrite') if not qtutils.confirm(title, msg, info_txt, ok_txt, default=False, icon=icons.save()): return self.accept()
def diff_helper(commit=None, ref=None, endref=None, filename=None, cached=True, head=None, amending=False, with_diff_header=False, suppress_header=True, reverse=False, git=git): "Invokes git diff on a filepath." if commit: ref, endref = commit+'^', commit argv = [] if ref and endref: argv.append('%s..%s' % (ref, endref)) elif ref: for r in utils.shell_split(ref.strip()): argv.append(r) elif head and amending and cached: argv.append(head) encoding = None if filename: argv.append('--') if type(filename) is list: argv.extend(filename) else: argv.append(filename) cfg = gitcfg.current() encoding = cfg.file_encoding(filename) if filename is not None: deleted = cached and not core.exists(filename) else: deleted = False status, out, err = git.diff(R=reverse, M=True, cached=cached, _encoding=encoding, *argv, **common_diff_opts()) if status != 0: # git init if with_diff_header: return ('', '') else: return '' return extract_diff_header(status, deleted, with_diff_header, suppress_header, out)
def save_archive(self): filename = self.filename if not filename: return if core.exists(filename): title = N_('Overwrite File?') msg = N_('The file "%s" exists and will be overwritten.') % filename info_txt = N_('Overwrite "%s"?') % filename ok_txt = N_('Overwrite') icon = qtutils.save_icon() if not qtutils.confirm(title, msg, info_txt, ok_txt, default=False, icon=icon): return self.accept()
def icon_file(filename, staged=False, untracked=False): """Returns a file path representing a corresponding file path.""" exists = True if staged: exists = core.exists(filename) if exists: ifile = resources.icon("staged-item.png") else: ifile = resources.icon("removed.png") elif untracked: ifile = resources.icon("untracked.png") else: (ifile, exists) = utils.file_icon(filename) return (ifile, exists)
def find_git(): """Return the path of git.exe, or None if we can't find it.""" if not utils.is_win32(): return None # UNIX systems have git in their $PATH # If the user wants to use a Git/bin/ directory from a non-standard # directory then they can write its location into # ~/.config/git-cola/git-bindir git_bindir = os.path.expanduser(os.path.join('~', '.config', 'git-cola', 'git-bindir')) if core.exists(git_bindir): custom_path = core.read(git_bindir).strip() if custom_path and core.exists(custom_path): return custom_path # Try to find Git's bin/ directory in one of the typical locations pf = os.environ.get('ProgramFiles', 'C:\\Program Files') pf32 = os.environ.get('ProgramFiles(x86)', 'C:\\Program Files (x86)') for p in [pf32, pf, 'C:\\']: candidate = os.path.join(p, 'Git\\bin') if os.path.isdir(candidate): return candidate return None
def _watch_directory(self, directory): """Set up a directory for monitoring by inotify""" if self._wmgr is None or self._add_watch_failed: return directory = core.realpath(directory) if directory in self._dirs_seen: return self._dirs_seen.add(directory) if core.exists(directory): dir_arg = directory if PY3 else core.encode(directory) try: self._wmgr.add_watch(dir_arg, self._mask, quiet=False) except WatchManagerError as e: self._add_watch_failed = True self._add_watch_failed_warning(directory, e)
def ident_file_type(filename): """Returns an icon based on the contents of filename.""" if core.exists(filename): filemimetype = mimetypes.guess_type(filename) if filemimetype[0] != None: for filetype, iconname in KNOWN_FILE_MIME_TYPES.items(): if filetype in filemimetype[0].lower(): return iconname filename = filename.lower() for fileext, iconname in KNOWN_FILE_EXTENSION.items(): if filename.endswith(fileext): return iconname return 'generic.png' else: return 'removed.png' # Fallback for modified files of an unknown type return 'generic.png'
def _load_dot_cola(self): values = {} path = os.path.join(core.expanduser('~'), '.cola') if not core.exists(path): return {} try: with core.xopen(path, 'r') as fp: json_values = json.load(fp) except: # bad json return {} # Keep only the entries we care about for key in self.values: try: values[key] = json_values[key] except KeyError: pass return values
def _create_staged_context_menu(self, menu, s): if s.staged[0] in self.m.submodules: return self._create_staged_submodule_context_menu(menu, s) if self.m.unstageable(): action = menu.addAction(qtutils.remove_icon(), N_('Unstage Selected'), cmds.run(cmds.Unstage, self.staged())) action.setShortcut(hotkeys.STAGE_SELECTION) # Do all of the selected items exist? all_exist = all(not i in self.m.staged_deleted and core.exists(i) for i in self.staged()) if all_exist: menu.addAction(self.launch_editor_action) menu.addAction(self.launch_difftool_action) if all_exist and not utils.is_win32(): menu.addSeparator() action = menu.addAction(qtutils.file_icon(), cmds.OpenDefaultApp.name(), cmds.run(cmds.OpenDefaultApp, self.staged())) action.setShortcut(hotkeys.PRIMARY_ACTION) action = menu.addAction(qtutils.open_file_icon(), cmds.OpenParentDir.name(), self._open_parent_dir) action.setShortcut(hotkeys.SECONDARY_ACTION) if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) menu.addSeparator() menu.addAction(self.copy_path_action) menu.addAction(self.copy_relpath_action) menu.addAction(self.view_history_action) return menu
def merge_message(revision): """Return a merge message for FETCH_HEAD.""" fetch_head = git.git_path('FETCH_HEAD') if core.exists(fetch_head): return git.fmt_merge_msg('--file', fetch_head)[STDOUT] return "Merge branch '%s'" % revision
def commit_message_path(): """Return the path to .git/GIT_COLA_MSG""" path = git.git_path("GIT_COLA_MSG") if core.exists(path): return path return None
def mimeData(self, items): """Return a list of absolute-path URLs""" paths = qtutils.paths_from_items(items, item_filter=lambda item: not item. deleted and core.exists(item.path)) return qtutils.mimedata_from_paths(paths)
def paths(self): all_refs = utils.shell_split(self.ref) if '--' in all_refs: all_refs = all_refs[all_refs.index('--'):] return [p for p in all_refs if p and core.exists(p)]
def _update_merge_rebase_status(self): self.is_merging = core.exists(self.git.git_path('MERGE_HEAD')) self.is_rebasing = core.exists(self.git.git_path('rebase-merge')) if self.is_merging and self.mode == self.mode_amend: self.set_mode(self.mode_none)
def contextMenuEvent(self, event): """Create the context menu for the diff display.""" menu = QtGui.QMenu(self) s = selection.selection() filename = selection.filename() if self.model.stageable(): if s.modified and s.modified[0] in main.model().submodules: action = menu.addAction(qtutils.icon('add.svg'), cmds.Stage.name(), cmds.run(cmds.Stage, s.modified)) action.setShortcut(cmds.Stage.SHORTCUT) menu.addAction( qtutils.git_icon(), N_('Launch git-cola'), cmds.run(cmds.OpenRepo, core.abspath(s.modified[0]))) elif s.modified: action = menu.addAction(qtutils.icon('add.svg'), N_('Stage Section'), self.stage_section) action.setShortcut(Qt.Key_H) menu.addAction(self.action_stage_selection) menu.addSeparator() menu.addAction(qtutils.icon('undo.svg'), N_('Revert Section...'), self.revert_section) menu.addAction(self.action_revert_selection) if self.model.unstageable(): if s.staged and s.staged[0] in main.model().submodules: action = menu.addAction(qtutils.icon('remove.svg'), cmds.Unstage.name(), cmds.do(cmds.Unstage, s.staged)) action.setShortcut(cmds.Unstage.SHORTCUT) menu.addAction( qtutils.git_icon(), N_('Launch git-cola'), cmds.do(cmds.OpenRepo, core.abspath(s.staged[0]))) elif s.staged: action = menu.addAction(qtutils.icon('remove.svg'), N_('Unstage Section'), self.unstage_section) action.setShortcut(Qt.Key_H) menu.addAction(self.action_unstage_selection) if self.model.stageable() or self.model.unstageable(): # Do not show the "edit" action when the file does not exist. # Untracked files exist by definition. if filename and core.exists(filename): menu.addSeparator() menu.addAction(self.launch_editor) # Removed files can still be diffed. menu.addAction(self.launch_difftool) menu.addSeparator() action = menu.addAction(qtutils.icon('edit-copy.svg'), N_('Copy'), self.copy) action.setShortcut(QtGui.QKeySequence.Copy) action = menu.addAction(qtutils.icon('edit-select-all.svg'), N_('Select All'), self.selectAll) action.setShortcut(QtGui.QKeySequence.SelectAll) menu.exec_(self.mapToGlobal(event.pos()))