Add check-ignore

This commit is contained in:
Nathan McRae 2024-07-07 20:06:28 -07:00
parent c2f8359690
commit 8fe3e19385

View File

@ -957,3 +957,110 @@ def cmd_ls_files(args):
print(f" uid: {e.uid} group: {e.gid}")
print(f" flags: stage={e.flag_stage} assume_valid={e.flag_assume_valid}")
argsp = argsubparsers.add_parser("check-ignore", help="Check path(s) against ignore rules.")
argsp.add_argument("path", nargs="+", help="Paths to check")
def cmd_check_ignore(args):
repo = repo_find()
rules = gitignore_read(repo)
for path in args.path:
if check_ignore(rules, path):
print(path)
def gitignore_parse1(raw):
raw = raw.strip()
if not raw or raw[0] == "#":
return None
elif raw[0] == "!":
return (raw[1:], False)
elif raw[0] == "\\":
return (raw[1:], True)
else:
return (raw, True)
def gitignore_parse(lines):
ret = list()
for line in lines:
parsed = gitignore_parse1(line)
if parsed:
ret.append(parsed)
return ret
class GitIgnore(object):
absolute = None
scoped = None
def __init__(self, absolute, scoped):
self.absolute = absolute
self.scoped = scoped
def gitignore_read(repo):
ret = GitIgnore(absolute=list(), scoped=dict())
# Read local configuration
repo_file = os.path.join(repo.gitdir, "info/exclude")
if os.path.exists(repo_file):
with open(repo_file, "r") as f:
ret.absolute.append(gitignore_parse(f.readlines()))
# Global configuration
if "XDG_CONFIG_HOME" in os.environ:
config_home == os.environ["XDG_CONFIG_HOME"]
else:
config_home = os.path.expanduser("~/.config")
global_file = os.path.join(config_home, "git/ignore")
if os.path.exists(global_file):
with open(global_file, "r") as f:
ret.absolute.append(gitignore_parse(f.readlines()))
# .gitignore files in the index
index = index_read(repo)
for entry in index.entries:
if entry.name == ".gitignore" or entry.name.endswith("/.gitignore"):
dir_name = os.path.dirname(entry.name)
contents = object_read(repo, entry.sha)
lines = contents.blobdata.decode("utf8").splitlines()
ret.scoped[dirname] = gitignore_parse(lines)
return ret
def check_ignore1(rules, path):
result = None
for (pattern, value) in rules:
if fnmatch(path, pattern):
result = value
return result
def check_ignore_scoped(rules, path):
parent = os.path.dirname(path)
while True:
if parent in rules:
result = check_ignore1(rules[parent], path)
if result != None:
return result
if parent == "":
break
parent = os.path.dirname(parent)
return None
def check_ignore_absolute(rules, path):
parent = os.path.dirname(path)
for ruleset in rules:
result = check_ignore1(ruleset, path)
if result != None:
return result
return False
def check_ignore(rules, path):
if os.path.isabs(path):
raise Exception("This function requires path to be relative to the repository's root")
result = check_ignore_scoped(rules.scoped, path)
if result != None:
return result
return check_ignore_absolute(rules.absolute, path)