<commit_before>"""Color items in the directory tree based on their git status."""
from __future__ import annotations

import logging
import os
import subprocess
import sys
import time
from concurrent.futures import Future, ThreadPoolExecutor
from functools import partial
from pathlib import Path
from typing import Any

from porcupine import utils
from porcupine.plugins.directory_tree import (
    DirectoryTree,
    FolderRefreshed,
    get_directory_tree,
    get_fg_and_bg_colors,
    get_path,
)

setup_after = ["directory_tree"]

log = logging.getLogger(__name__)

# Each git subprocess uses one cpu core
git_pool = ThreadPoolExecutor(max_workers=os.cpu_count())


def run_git_status(project_root: Path) -> dict[Path, str]:
    try:
        start = time.perf_counter()
        run_result = subprocess.run(
            # For debugging: ["bash", "-c", "sleep 1 && git status --ignored --porcelain"],
            ["git", "status", "--ignored", "--porcelain"],
            cwd=project_root,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,  # for logging error message
            encoding=sys.getfilesystemencoding(),
            timeout=15,  # Must be huge to avoid unnecessary killing #885
            **utils.subprocess_kwargs,
        )
        log.debug(
            f"running git status in {project_root} took"
            f" {round((time.perf_counter() - start)*1000)}ms"
        )

        if run_result.returncode != 0:
            # likely not a git repo because missing ".git" dir
            log.debug(f"git status failed in {project_root}: {run_result}")
            return {}<commit_msg>Give "git status" a really long timeout (#1085)<commit_after>"""Color items in the directory tree based on their git status."""
from __future__ import annotations

import logging
import os
import subprocess
import sys
import time
from concurrent.futures import Future, ThreadPoolExecutor
from functools import partial
from pathlib import Path
from typing import Any

from porcupine import utils
from porcupine.plugins.directory_tree import (
    DirectoryTree,
    FolderRefreshed,
    get_directory_tree,
    get_fg_and_bg_colors,
    get_path,
)

setup_after = ["directory_tree"]

log = logging.getLogger(__name__)

# Each git subprocess uses one cpu core
git_pool = ThreadPoolExecutor(max_workers=os.cpu_count())


def run_git_status(project_root: Path) -> dict[Path, str]:
    try:
        start = time.perf_counter()
        run_result = subprocess.run(
            # For debugging: ["bash", "-c", "sleep 1 && git status --ignored --porcelain"],
            ["git", "status", "--ignored", "--porcelain"],
            cwd=project_root,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,  # for logging error message
            encoding=sys.getfilesystemencoding(),
            timeout=(60 * 10),  # 10min. Must be huge to avoid unnecessary killing (#885)
            **utils.subprocess_kwargs,
        )
        log.debug(
            f"running git status in {project_root} took"
            f" {round((time.perf_counter() - start)*1000)}ms"
        )

        if run_result.returncode != 0:
            # likely not a git repo because missing ".git" dir
            log.debug(f"git status failed in {project_root}: {run_result}")
            return {}
{'fraction_non_alphanumeric': 0.09770114942528736, 'fraction_numerical': 0.009074410163339383, 'mean_word_length': 2.8633177570093458, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6936648', 'n_tokens_mistral': 966, 'n_tokens_neox': 923, 'n_words': 285}