Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 34 additions & 35 deletions gitignore_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
def start(): # Gets invoked at the bottom of this file.
"""
Regularly (every 5s) updates the file_exclude_patterns setting.
"""
"""
if is_first_launch():
migrate_exclude_patterns()
record_first_launch()

def run():
update_file_exclude_patterns()
sublime.set_timeout(run, 5000)
Expand All @@ -38,13 +38,13 @@ def update_file_exclude_patterns():
"""
Updates the "file_exclude_patterns" preference to include all .gitignored
files.

Also includes any additional files or folders listed in the
"extra_file_exclude_patterns" and "extra_folder_exclude_patterns" settings.
"""
s = sublime.load_settings("Preferences.sublime-settings")
file_exclude_patterns = s.get('extra_file_exclude_patterns', [])
folder_exclude_patterns = s.get('extra_folder_exclude_patterns', [])
file_exclude_patterns = s.get('extra_file_exclude_patterns', []) or []
folder_exclude_patterns = s.get('extra_folder_exclude_patterns', []) or []
for path in all_ignored_paths():
is_directory = os.path.isdir(path)
if platform.system() == 'Windows':
Expand All @@ -63,13 +63,13 @@ def update_file_exclude_patterns():
file_exclude_patterns.append(path)

new_files = set(file_exclude_patterns)
old_files = set(s.get('file_exclude_patterns', []))
old_files = set(s.get('file_exclude_patterns', []) or [])
new_folders = set(folder_exclude_patterns)
old_folders = set(s.get('folder_exclude_patterns', []))
old_folders = set(s.get('folder_exclude_patterns', []) or [])

# Only make changes if anything has actually changed, to avoid spamming the
# sublime console
if new_files != old_files or new_folders != old_folders:
if new_files != old_files or new_folders != old_folders:
s.set('file_exclude_patterns', list(file_exclude_patterns))
s.set('folder_exclude_patterns', list(folder_exclude_patterns))
sublime.save_settings("Preferences.sublime-settings")
Expand All @@ -79,32 +79,32 @@ def all_ignored_paths():
Returns a list of all .gitignored files or folders contained in repos
contained within or containing any folders open in any open windows.
"""

open_folders = set()
for window in sublime.windows():
open_folders.update(window.folders())

all_ignored_paths = set()
for folder in open_folders:
ignored_paths = folder_ignored_paths(folder)
all_ignored_paths.update(ignored_paths)

return list(all_ignored_paths)

def folder_ignored_paths(folder):
"""
Returns a list (without duplicates, in the case of weird repo-nesting) of
all files/folders within the given folder that are git ignored.
The folder itself need not be the top level of a git repo, nor even within

The folder itself need not be the top level of a git repo, nor even within
a git repo.
"""

all_ignored_paths = set()

# First find all repos CONTAINED in this folder:
repos = set(find_git_repos(folder))

# Then, additionally, if this folder is itself contained within a repo,
# find the .git folder of the repo containing it:
if is_in_git_repo(folder):
Expand All @@ -114,30 +114,30 @@ def folder_ignored_paths(folder):
for git_repo in repos:
ignored_paths = repo_ignored_paths(git_repo)
all_ignored_paths.update(ignored_paths)

return list(all_ignored_paths)

def is_in_git_repo(folder):
"""
Returns true if the given folder is contained within a git repo
"""

exit_code = subprocess.call(
["git", "rev-parse", "--is-inside-work-tree"],
cwd=folder,
stdout=devnull,
stderr=devnull,
startupinfo=startupinfo
)

return exit_code == 0

def parent_repo_path(folder):
"""
Takes the path to a folder contained within a git repo, and returns the
parent repo.
"""

# abspath call converts forward slashes to backslashes on Windows; we do
# this wherever necessary to keep the format of our paths standardised on
# Windows.
Expand All @@ -154,7 +154,7 @@ def find_git_repos(folder):
"""
Returns a list of all git repos within the given ancestor folder.
"""

return [root for root, subfolders, files
in os.walk(folder)
if '.git' in subfolders]
Expand All @@ -164,7 +164,7 @@ def repo_ignored_paths(git_repo):
Takes the path of a git repo and lists all ignored files/folders in the
repo.
"""

# Trick for listing ignored files nicked from
# http://stackoverflow.com/a/2196755/1709587
command_output = subprocess.Popen(
Expand All @@ -174,38 +174,37 @@ def repo_ignored_paths(git_repo):
startupinfo=startupinfo,
env={'LANG':'C'}
).stdout.read()

command_output = command_output.decode('utf-8', 'ignore')

if command_output.isspace() or command_output == u'':
return []
return []

lines = command_output.strip().split(u'\n')
# Each line in `lines` now looks something like:
# "Would remove foo/bar/yourfile.txt"

relative_paths = [line.replace(u'Would remove ', u'', 1).rstrip(u'/')
for line in lines]
absolute_paths = [os.path.join(git_repo, path) for path in relative_paths]

return absolute_paths

def is_first_launch():
s = sublime.load_settings("gitignorer.sublime-settings")
return not s.get('_sublime_gitignorer_has_run', False)

def migrate_exclude_patterns():
"""
Runs on first launch; purpose is to prevent people who have already set
exclusion patterns from losing them when they install this package.
"""
s = sublime.load_settings("Preferences.sublime-settings")
existing_file_exclude_patterns = s.get('file_exclude_patterns', [])
existing_folder_exclude_patterns = s.get('folder_exclude_patterns', [])
existing_file_exclude_patterns = s.get('file_exclude_patterns', []) or []
existing_folder_exclude_patterns = s.get('folder_exclude_patterns', []) or []
s.set('extra_file_exclude_patterns', existing_file_exclude_patterns)
s.set('extra_folder_exclude_patterns', existing_folder_exclude_patterns)
sublime.save_settings("Preferences.sublime-settings")

def record_first_launch():
s = sublime.load_settings("gitignorer.sublime-settings")
s.set('_sublime_gitignorer_has_run', True)
Expand All @@ -225,5 +224,5 @@ def windows_path_to_sublime_path(path):
assert(path[1] == u':')
without_colon = path[0] + path[2:]
return without_colon.replace(u'\\', u'/')

start()