diff --git a/main.py b/main.py index a7a766d..eb24591 100755 --- a/main.py +++ b/main.py @@ -5,6 +5,7 @@ import yaml import argparse import json import os +import sys # Define configuration file paths. USER_CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "config", "config.yaml") @@ -105,6 +106,19 @@ For detailed help on each command, use: delete_parser = subparsers.add_parser("delete", help="Delete repository/repositories alias links to executables") add_identifier_arguments(delete_parser) + + # Add the 'create' subcommand (with existing identifier arguments) + create_parser = subparsers.add_parser( + "create", + help="Create new repository entries: add them to the config if not already present, initialize the local repository, and push remotely if --remote is set." + ) + # Reuse the common identifier arguments + add_identifier_arguments(create_parser) + create_parser.add_argument( + "--remote", + action="store_true", + help="If set, add the remote and push the initial commit." + ) update_parser = subparsers.add_parser("update", help="Update (pull + install) repository/repositories") add_identifier_arguments(update_parser) @@ -170,6 +184,16 @@ For detailed help on each command, use: # Dispatch commands. if args.command == "install": install_repos(selected,repositories_base_dir, BIN_DIR, all_repos_list, args.no_verification, preview=args.preview, quiet=args.quiet) + elif args.command == "create": + from pkgmgr.create_repo import create_repo + # If no identifiers are provided, you can decide to either use the repository of the current folder + # or prompt the user to supply at least one identifier. + if not args.identifiers: + print("No identifiers provided. Please specify at least one identifier in the format provider/account/repository.") + sys.exit(1) + else: + for identifier in args.identifiers: + create_repo(identifier, config_merged, USER_CONFIG_PATH, BIN_DIR, remote=args.remote, preview=args.preview) elif args.command in GIT_DEFAULT_COMMANDS: if args.command == "clone": clone_repos(selected, repositories_base_dir, all_repos_list, args.preview, no_verification=args.no_verification) @@ -226,7 +250,7 @@ For detailed help on each command, use: elif args.command == "shell": if not args.shell_command: print("No shell command specified.") - exit(1) + exit(2) # Join the provided shell command parts into one string. command_to_run = " ".join(args.shell_command) for repository in selected: diff --git a/pkgmgr/create_repo.py b/pkgmgr/create_repo.py new file mode 100644 index 0000000..1fca709 --- /dev/null +++ b/pkgmgr/create_repo.py @@ -0,0 +1,100 @@ +import os +import subprocess +import yaml +from pkgmgr.generate_alias import generate_alias +from pkgmgr.save_user_config import save_user_config + +def create_repo(identifier, config_merged, user_config_path, bin_dir, remote=False, preview=False): + """ + Creates a new repository by performing the following steps: + + 1. Parses the identifier (provider/account/repository) and adds a new entry to the user config + if it is not already present. + 2. Creates the local repository directory and initializes a Git repository. + 3. If --remote is set, adds a remote, creates an initial commit (e.g. with a README.md), and pushes to remote. + """ + parts = identifier.split("/") + if len(parts) != 3: + print("Identifier must be in the format 'provider/account/repository'.") + return + + provider, account, repository = parts + + # Check if the repository is already present in the merged config + exists = False + for repo in config_merged.get("repositories", []): + if repo.get("provider") == provider and repo.get("account") == account and repo.get("repository") == repository: + exists = True + print(f"Repository {identifier} already exists in the configuration.") + break + + if not exists: + # Create a new entry with an automatically generated alias + new_entry = { + "provider": provider, + "account": account, + "repository": repository, + "alias": generate_alias({"repository": repository, "provider": provider, "account": account}, bin_dir, existing_aliases=set()), + "verified": {} # No initial verification info + } + # Load or initialize the user configuration + if os.path.exists(user_config_path): + with open(user_config_path, "r") as f: + user_config = yaml.safe_load(f) or {} + else: + user_config = {"repositories": []} + user_config.setdefault("repositories", []) + user_config["repositories"].append(new_entry) + save_user_config(user_config, user_config_path) + print(f"Repository {identifier} added to the configuration.") + # Also update the merged configuration object + config_merged.setdefault("repositories", []).append(new_entry) + + # Create the local repository directory based on the configured base directory + base_dir = os.path.expanduser(config_merged["directories"]["repositories"]) + repo_dir = os.path.join(base_dir, provider, account, repository) + if not os.path.exists(repo_dir): + os.makedirs(repo_dir, exist_ok=True) + print(f"Local repository directory created: {repo_dir}") + else: + print(f"Local repository directory already exists: {repo_dir}") + + # Initialize a Git repository if not already initialized + if not os.path.exists(os.path.join(repo_dir, ".git")): + cmd_init = "git init" + if preview: + print(f"[Preview] Would execute: '{cmd_init}' in {repo_dir}") + else: + subprocess.run(cmd_init, cwd=repo_dir, shell=True, check=True) + print(f"Git repository initialized in {repo_dir}.") + else: + print("Git repository is already initialized.") + + if remote: + # Create a README.md if it does not exist to have content for an initial commit + readme_path = os.path.join(repo_dir, "README.md") + if not os.path.exists(readme_path): + if preview: + print(f"[Preview] Would create README.md in {repo_dir}.") + else: + with open(readme_path, "w") as f: + f.write(f"# {repository}\n") + subprocess.run("git add README.md", cwd=repo_dir, shell=True, check=True) + subprocess.run('git commit -m "Initial commit"', cwd=repo_dir, shell=True, check=True) + print("README.md created and initial commit made.") + # Add a remote named "origin" + remote_url = f"git@{provider}:{account}/{repository}.git" + cmd_remote = f"git remote add origin {remote_url}" + if preview: + print(f"[Preview] Would execute: '{cmd_remote}' in {repo_dir}") + else: + subprocess.run(cmd_remote, cwd=repo_dir, shell=True, check=True) + print(f"Remote 'origin' added: {remote_url}") + # Push the initial commit to the remote repository + cmd_push = "git push -u origin master" + if preview: + print(f"[Preview] Would execute: '{cmd_push}' in {repo_dir}") + else: + subprocess.run(cmd_push, cwd=repo_dir, shell=True, check=True) + print("Initial push to the remote repository completed.") + exit(7) \ No newline at end of file diff --git a/pkgmgr/get_repo_dir.py b/pkgmgr/get_repo_dir.py index e154aea..68fa3b8 100644 --- a/pkgmgr/get_repo_dir.py +++ b/pkgmgr/get_repo_dir.py @@ -12,4 +12,4 @@ def get_repo_dir(repositories_base_dir:str,repo:{})->str: print(f"Key '{key}' is missing.") else: print(f"Error: {e} \nThe base {base} seems not correct configured.\nPlease configure it correct.") - sys.exit(1) \ No newline at end of file + sys.exit(3) \ No newline at end of file diff --git a/pkgmgr/get_selected_repos.py b/pkgmgr/get_selected_repos.py index 4aae65d..23a8bfc 100644 --- a/pkgmgr/get_selected_repos.py +++ b/pkgmgr/get_selected_repos.py @@ -25,5 +25,5 @@ def get_selected_repos(show_all: bool, all_repos_list, identifiers=None): filtered = filter_ignored(selected) if not filtered: print("Error: No repositories had been selected.") - sys.exit(1) + sys.exit(4) return filtered diff --git a/pkgmgr/load_config.py b/pkgmgr/load_config.py index 0022968..8b93194 100644 --- a/pkgmgr/load_config.py +++ b/pkgmgr/load_config.py @@ -8,12 +8,12 @@ def load_config(user_config_path): """Load configuration from defaults and merge in user config if present.""" if not os.path.exists(DEFAULT_CONFIG_PATH): print(f"Default configuration file '{DEFAULT_CONFIG_PATH}' not found.") - sys.exit(1) + sys.exit(5) with open(DEFAULT_CONFIG_PATH, 'r') as f: config = yaml.safe_load(f) if "directories" not in config or "repositories" not in config: print("Default config file must contain 'directories' and 'repositories' keys.") - sys.exit(1) + sys.exit(6) if os.path.exists(user_config_path): with open(user_config_path, 'r') as f: user_config = yaml.safe_load(f)