diff --git a/pyproject.toml b/pyproject.toml index c4cda2c..3eb5153 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "vana" -version = "0.24.0" +version = "0.25.0" description = "" authors = ["Tim Nunamaker ", "Volodymyr Isai ", "Kahtaf Alam "] readme = "README.md" @@ -31,7 +31,7 @@ tomli = "^2.1.0" [build-system] -requires = ["poetry-core", "setuptools>=42", "wheel"] +requires = ["poetry-core", "setuptools>=42", "wheel", "tomli>=2.0.0"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] diff --git a/setup.py b/setup.py index 9ff6e28..ef53968 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,10 @@ from setuptools import setup, find_packages +from setuptools.command.install import install +from distutils.cmd import Command +from typing import Dict, Type, cast import tomli +import subprocess +import sys with open("pyproject.toml", "rb") as f: pyproject = tomli.load(f) @@ -13,6 +18,24 @@ if pkg != "python" ] + +class PostInstallCommand(install): + """Custom command that runs PATH setup after installation""" + + def run(self) -> None: + """Run install and then update PATH""" + install.run(self) + try: + # Run vanacli with post-install flag + subprocess.run([sys.executable, "-m", "vana.cli", "--post-install"], check=True) + except subprocess.CalledProcessError: + print("Warning: Failed to update PATH configuration", file=sys.stderr) + + +command_classes = cast(Dict[str, Type[Command]], { + 'install': PostInstallCommand +}) + setup( name="vana", version=version, @@ -24,4 +47,5 @@ ], }, python_requires=pyproject["tool"]["poetry"]["dependencies"]["python"], + cmdclass=command_classes ) diff --git a/vana/__init__.py b/vana/__init__.py index 00dcf56..f54e692 100644 --- a/vana/__init__.py +++ b/vana/__init__.py @@ -15,7 +15,7 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -__version__ = "0.24.0" +__version__ = "0.25.0" import rich diff --git a/vana/cli.py b/vana/cli.py index 59c4436..a2fd30e 100644 --- a/vana/cli.py +++ b/vana/cli.py @@ -20,6 +20,8 @@ import argparse import shtab import sys +import os +from pathlib import Path import vana from importlib.metadata import entry_points from typing import List, Optional @@ -119,6 +121,39 @@ } +def ensure_local_bin_in_path(): + """Ensures ~/.local/bin is in PATH for the current session""" + local_bin = str(Path.home() / ".local" / "bin") + if local_bin not in os.environ.get("PATH", "").split(os.pathsep): + os.environ["PATH"] = local_bin + os.pathsep + os.environ.get("PATH", "") + + +def update_shell_config(): + """Updates shell config to include ~/.local/bin in PATH""" + local_bin = str(Path.home() / ".local" / "bin") + + # Check if already in PATH + if local_bin in os.environ.get("PATH", "").split(os.pathsep): + return + + # Determine shell config file + shell = os.environ.get("SHELL", "") + home = str(Path.home()) + + if "zsh" in shell: + rc_file = os.path.join(home, ".zshrc") + else: # default to bash + rc_file = os.path.join(home, ".bashrc") + + if os.path.exists(rc_file): + with open(rc_file, 'r') as f: + content = f.read() + + if "PATH=\"$HOME/.local/bin:$PATH\"" not in content: + with open(rc_file, 'a') as f: + f.write('\n# Added by vana installation\nexport PATH="$HOME/.local/bin:$PATH"\n') + + def load_external_commands(): """ Load external commands from entry points. @@ -133,6 +168,7 @@ def load_external_commands(): except Exception as e: pass + class CLIErrorParser(argparse.ArgumentParser): """ Custom ArgumentParser for better error messages. @@ -185,6 +221,9 @@ def __init__( # Check if the config is valid. cli.check_config(self.config) + # Ensure ~/.local/bin is in PATH + ensure_local_bin_in_path() + # If no_version_checking is not set or set as False in the config, version checking is done. if not self.config.get("no_version_checking", d=True): try: @@ -215,6 +254,11 @@ def __create_parser__() -> "argparse.ArgumentParser": choices=shtab.SUPPORTED_SHELLS, help="Print shell tab completion script", ) + parser.add_argument( + "--post-install", + action="store_true", + help=argparse.SUPPRESS, # Hide from help output + ) # Add arguments for each sub-command. cmd_parsers = parser.add_subparsers(dest="command") # Add argument parsers for all available commands. @@ -319,6 +363,12 @@ def main(): parser = cli.__create_parser__() args, unknown = parser.parse_known_args() + # Handle post-install PATH setup + if getattr(args, 'post_install', False): + update_shell_config() + ensure_local_bin_in_path() + return + if args.print_completion: # Check for print-completion argument print(shtab.complete(parser, args.print_completion)) return