Skip to content

Commit fc02165

Browse files
committed
ci-bump-version
1 parent 0d9385c commit fc02165

8 files changed

Lines changed: 765 additions & 815 deletions

File tree

codeconcat/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- coding: utf-8 -*-
2+
# codeconcat/__init__.py
3+
try:
4+
from importlib.metadata import PackageNotFoundError, version
5+
6+
try:
7+
__version__ = version("codeconcat")
8+
except PackageNotFoundError:
9+
# Package is not installed, perhaps running from source
10+
__version__ = "0.0.0-dev"
11+
except ImportError:
12+
# Fallback for Python < 3.8
13+
import pkg_resources
14+
15+
try:
16+
__version__ = pkg_resources.get_distribution("codeconcat").version
17+
except pkg_resources.DistributionNotFound:
18+
__version__ = "0.0.0-dev"
19+
20+
# You can also import key functions here if you want them accessible like:
21+
# from .main import main

codeconcat/cli.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@
5353
default=False,
5454
help="Disable processing of .gitignore files.",
5555
)
56-
parser.add_argument(
57-
"-v", "--verbose", action="store_true", help="Enable verbose logging (DEBUG level)."
58-
)
56+
parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose logging (DEBUG level).")
5957

6058

6159
def parse_arguments(args: Optional[List[str]] = None) -> argparse.Namespace:

codeconcat/config.py

Lines changed: 67 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -3,178 +3,79 @@
33
import json
44
import logging
55
from pathlib import Path
6-
7-
# Use typing.Tuple for broader compatibility if MyPy struggles with tuple[]
8-
from typing import Dict, List, Set, Tuple
6+
from typing import Any, Dict, Optional
97

108
logger = logging.getLogger(__name__)
119

12-
# --- Constants ---
13-
14-
CONFIG_FILE_NAME = ".codeconcat_config.json"
15-
GITIGNORE_FILE_NAME = ".gitignore"
16-
17-
# Heuristic: MIME types that are likely binary or not useful text content
18-
# Use typing.Tuple explicitly
19-
EXCLUDED_MIME_PREFIXES: Tuple[str, ...] = ("application/", "image/", "audio/", "video/")
20-
21-
# Common text/code file extensions (Set for faster lookups)
22-
DEFAULT_WHITELIST_EXTENSIONS: Set[str] = {
23-
# Code
24-
".py",
25-
".pyw",
26-
".pyi",
27-
".js",
28-
".mjs",
29-
".cjs",
30-
".ts",
31-
".tsx",
32-
".java",
33-
".c",
34-
".h",
35-
".cpp",
36-
".hpp",
37-
".cs",
38-
".rb",
39-
".php",
40-
".swift",
41-
".go",
42-
".rs",
43-
".kt",
44-
".kts",
45-
".scala",
46-
".pl",
47-
".pm",
48-
".sh",
49-
".bash",
50-
".zsh",
51-
".ps1",
52-
".lua",
53-
".sql",
54-
".r",
55-
".dart",
56-
".groovy",
57-
".hs",
58-
".lhs",
59-
".ml",
60-
".mli",
61-
".fs",
62-
".fsx",
63-
".fsi",
64-
".elm",
65-
".clj",
66-
".cljs",
67-
".edn",
68-
".ex",
69-
".exs",
70-
".erl",
71-
".hrl",
72-
".vim",
73-
".el",
74-
# Markup & Config
75-
".html",
76-
".htm",
77-
".css",
78-
".scss",
79-
".sass",
80-
".less",
81-
".xml",
82-
".json",
83-
".yaml",
84-
".yml",
85-
".toml",
86-
".ini",
87-
".cfg",
88-
".conf",
89-
".properties",
90-
".md",
91-
".markdown",
92-
".rst",
93-
".adoc",
94-
".asciidoc",
95-
".tex",
96-
".bib",
97-
".csv",
98-
".tsv",
99-
".log",
100-
".txt",
101-
".env",
102-
".dockerfile",
103-
"dockerfile",
104-
".gitignore",
105-
".gitattributes",
106-
".editorconfig",
107-
# Other potentially useful text
108-
".nfo",
109-
".readme",
110-
".inf",
111-
".url",
10+
HOME_CONFIG_PATH = Path.home() / ".codeconcat_config.json"
11+
PROJECT_CONFIG_PATH = Path(".") / ".codeconcat_config.json"
12+
13+
DEFAULT_CONFIG: Dict[str, Any] = {
14+
"use_gitignore": True,
15+
"exclude_patterns": [],
16+
"whitelist_patterns": [],
17+
# Add other future config options here with defaults
11218
}
11319

114-
# Default patterns to exclude (common build artifacts, caches, envs, etc.)
115-
DEFAULT_EXCLUDE_PATTERNS: List[str] = [
116-
".*",
117-
"__pycache__",
118-
"*.pyc",
119-
"*.pyo",
120-
"*.pyd",
121-
"*.so",
122-
"*.o",
123-
"*.a",
124-
"*.dll",
125-
"*.exe",
126-
"node_modules",
127-
"vendor",
128-
"build",
129-
"dist",
130-
"target",
131-
"*.egg-info",
132-
".venv",
133-
"venv",
134-
"env",
135-
".env",
136-
".pytest_cache",
137-
".mypy_cache",
138-
".ruff_cache",
139-
"*.lock",
140-
"package-lock.json",
141-
"yarn.lock",
142-
"poetry.lock",
143-
"Pipfile.lock",
144-
"*.swp",
145-
"*.swo",
146-
]
147-
148-
# --- Functions ---
149-
150-
151-
def load_config(config_path: Path) -> Dict[str, List[str]]:
20+
# Flag to ensure default config creation happens only once per run if needed
21+
_default_config_created = False
22+
23+
24+
def load_config_file(path: Path) -> Optional[Dict[str, Any]]:
15225
"""Loads configuration from a JSON file."""
153-
config: Dict[str, List[str]] = {"exclude": [], "whitelist": []}
154-
if config_path.is_file():
26+
if path.is_file():
15527
try:
156-
with config_path.open("r", encoding="utf-8") as f:
157-
data = json.load(f)
158-
loaded_exclude = data.get("exclude")
159-
loaded_whitelist = data.get("whitelist")
160-
if isinstance(loaded_exclude, list):
161-
config["exclude"] = [
162-
str(p) for p in loaded_exclude if isinstance(p, str)
163-
]
164-
if isinstance(loaded_whitelist, list):
165-
config["whitelist"] = [
166-
str(p) for p in loaded_whitelist if isinstance(p, str)
167-
]
168-
logger.info(f"Loaded configuration from {config_path}")
28+
with open(path, "r", encoding="utf-8") as f:
29+
return json.load(f)
16930
except json.JSONDecodeError:
170-
logger.warning(
171-
f"Could not decode JSON from {config_path}. Using defaults/CLI args."
172-
)
173-
except Exception as e:
174-
logger.warning(
175-
f"Error reading config file {config_path}: {e}. "
176-
"Using defaults/CLI args."
177-
)
178-
else:
179-
logger.debug(f"No config file found at {config_path}.")
31+
logger.warning(f"Could not decode JSON from config file: {path}")
32+
except OSError as e:
33+
logger.warning(f"Could not read config file: {path}. Error: {e}")
34+
return None
35+
36+
37+
def merge_configs(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
38+
"""Merges two config dictionaries. Override takes precedence."""
39+
merged = base.copy()
40+
for key, value in override.items():
41+
if key in merged and isinstance(merged[key], list) and isinstance(value, list):
42+
# Combine lists for patterns? Or override? Let's override for simplicity.
43+
# Ensure uniqueness if combining later.
44+
merged[key] = value
45+
else:
46+
merged[key] = value
47+
return merged
48+
49+
50+
def get_config() -> Dict[str, Any]:
51+
"""Loads configuration from home and project files, merging them."""
52+
config = DEFAULT_CONFIG.copy()
53+
54+
home_config = load_config_file(HOME_CONFIG_PATH)
55+
if home_config:
56+
config = merge_configs(config, home_config)
57+
logger.info(f"Loaded configuration from {HOME_CONFIG_PATH}")
58+
59+
project_config = load_config_file(PROJECT_CONFIG_PATH)
60+
if project_config:
61+
config = merge_configs(config, project_config)
62+
logger.info(f"Loaded configuration from {PROJECT_CONFIG_PATH} (overrides home config)")
63+
64+
# Create default home config only if neither home nor project config existed
65+
if not home_config and not project_config:
66+
create_default_config_if_needed(HOME_CONFIG_PATH)
67+
18068
return config
69+
70+
71+
def create_default_config_if_needed(path: Path) -> None:
72+
"""Creates a default config file at the specified path if it doesn't exist."""
73+
global _default_config_created
74+
if not path.exists() and not _default_config_created:
75+
try:
76+
with open(path, "w", encoding="utf-8") as f:
77+
json.dump(DEFAULT_CONFIG, f, indent=2)
78+
logger.info(f"Created default configuration file at: {path}")
79+
_default_config_created = True # Mark as created for this run
80+
except OSError as e:
81+
logger.warning(f"Could not create default config file at {path}. Error: {e}")

0 commit comments

Comments
 (0)