Skip to content
Snippets Groups Projects
Commit f9750937 authored by Leo's avatar Leo
Browse files

chore(comments): Add better docs

parent 5bd42058
No related branches found
No related tags found
No related merge requests found
Pipeline #291438 passed
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="2f47370d-26d1-4fc6-a93f-363c8b4c6e5a" name="Changes" comment=""> <list default="true" id="2f47370d-26d1-4fc6-a93f-363c8b4c6e5a" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.gitlab-ci.yml" beforeDir="false" afterPath="$PROJECT_DIR$/.gitlab-ci.yml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gpm/cli.py" beforeDir="false" afterPath="$PROJECT_DIR$/gpm/cli.py" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
...@@ -83,7 +84,7 @@ ...@@ -83,7 +84,7 @@
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1724140762915</updated> <updated>1724140762915</updated>
<workItem from="1724140765116" duration="10726000" /> <workItem from="1724140765116" duration="10726000" />
<workItem from="1724224393281" duration="8004000" /> <workItem from="1724224393281" duration="8838000" />
</task> </task>
<servers /> <servers />
</component> </component>
......
...@@ -53,6 +53,10 @@ def find_best_match(query, options): ...@@ -53,6 +53,10 @@ def find_best_match(query, options):
def setup(): def setup():
"""
Setup the CLI parser, handle argument- and subcommand parsing.
:return:
"""
if not os.path.exists(data_location): if not os.path.exists(data_location):
os.makedirs(data_location) os.makedirs(data_location)
if not os.path.exists(data_file): if not os.path.exists(data_file):
...@@ -121,6 +125,10 @@ def setup(): ...@@ -121,6 +125,10 @@ def setup():
@dataclass @dataclass
class Profile: class Profile:
"""
Dataclass for a git profile.
Represents a git profile with a name, email and optional comment.
"""
name: str name: str
email: str email: str
comment: Optional[str] = None comment: Optional[str] = None
...@@ -135,12 +143,23 @@ class Profile: ...@@ -135,12 +143,23 @@ class Profile:
class GPM: class GPM:
"""
Git Profile Manager class. Otherwise known as the Main Program
"""
def __init__(self, use_global_git_config=False): def __init__(self, use_global_git_config=False):
"""
Initialize the Git Profile Manager
:param use_global_git_config: Whether to use the global git config or not, when initializing the class
"""
self.profiles = [] self.profiles = []
self._load() self._load() # Load profiles from file `data_file`
self.use_global_git_config = use_global_git_config self.use_global_git_config = use_global_git_config
def _load(self): def _load(self):
"""
Load profiles from the data file
:return: List of profiles
"""
with open(data_file, "r") as f: with open(data_file, "r") as f:
data = json.load(f) data = json.load(f)
try: try:
...@@ -149,11 +168,22 @@ class GPM: ...@@ -149,11 +168,22 @@ class GPM:
print(f"{colorama.Fore.RED}Error loading profiles{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}Error loading profiles{colorama.Style.RESET_ALL}")
sys.exit(1) sys.exit(1)
def _save(self): def _save(self) -> None:
"""
Save the profiles to the data file
:return: None
"""
with open(data_file, "w") as f: with open(data_file, "w") as f:
json.dump([profile.__dict__ for profile in self.profiles], f, indent=4) json.dump([profile.__dict__ for profile in self.profiles], f, indent=4)
def add(self, name, email, comment=None): def add(self, name, email, comment=None):
"""
Add a new profile to the list of profiles
:param name: The name of the profile
:param email: The email of the profile
:param comment: Optional comment for the profile
:return: None
"""
# Validate name and email # Validate name and email
if not re.match(r"[^@]+@[^@]+\.[^@]+", email): if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
print(f"{colorama.Fore.RED}Invalid email{colorama.Style.RESET_ALL}: {email}") print(f"{colorama.Fore.RED}Invalid email{colorama.Style.RESET_ALL}: {email}")
...@@ -161,6 +191,8 @@ class GPM: ...@@ -161,6 +191,8 @@ class GPM:
if not name: if not name:
print(f"{colorama.Fore.RED}Name cannot be empty{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}Name cannot be empty{colorama.Style.RESET_ALL}")
return return
# Check if profile already exists
for profile in self.profiles: for profile in self.profiles:
if profile.email == email: if profile.email == email:
print(f"{colorama.Fore.RED}Email {email} already exists{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}Email {email} already exists{colorama.Style.RESET_ALL}")
...@@ -168,10 +200,17 @@ class GPM: ...@@ -168,10 +200,17 @@ class GPM:
profile = Profile(name, email, comment) profile = Profile(name, email, comment)
self.profiles.append(profile) self.profiles.append(profile)
self._save() self._save()
#print(f"Added profile: {name} <{email}>")
print(f"{colorama.Fore.GREEN}Added profile: {self.get_profile_format(profile)}") print(f"{colorama.Fore.GREEN}Added profile: {self.get_profile_format(profile)}")
def edit(self, query, name=None, email=None, comment=None): def edit(self, query, name=None, email=None, comment=None):
"""
Edit an existing profile
:param query: The query to match the profile to edit
:param name: If provided, the new name for the profile
:param email: If provided, the new email for the profile
:param comment: If provided, the new comment for the profile
:return:
"""
if not name and not email and not comment: if not name and not email and not comment:
print(f"{colorama.Fore.RED}Nothing to edit{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}Nothing to edit{colorama.Style.RESET_ALL}")
return return
...@@ -188,6 +227,10 @@ class GPM: ...@@ -188,6 +227,10 @@ class GPM:
print(f"{colorama.Fore.GREEN}Edited profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.GREEN}Edited profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}")
def list(self): def list(self):
"""
List all profiles
:return: None
"""
if not self.profiles: if not self.profiles:
print(f"{colorama.Fore.YELLOW}No profiles found{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No profiles found{colorama.Style.RESET_ALL}")
else: else:
...@@ -195,7 +238,12 @@ class GPM: ...@@ -195,7 +238,12 @@ class GPM:
print(f" {index}. {profile}") print(f" {index}. {profile}")
def match_query_to_profile(self, query: str): def match_query_to_profile(self, query: str) -> Optional[Profile]:
"""
Match a query to a profile
:param query: The query to match
:return: The profile if found, otherwise None
"""
if query.isdigit(): if query.isdigit():
index = int(query) - 1 index = int(query) - 1
if index < 0 or index >= len(self.profiles): if index < 0 or index >= len(self.profiles):
...@@ -222,15 +270,30 @@ class GPM: ...@@ -222,15 +270,30 @@ class GPM:
return profile return profile
def get_profile_format(self, profile: Profile): def get_profile_format(self, profile: Profile):
"""
Get the formatted profile string
:param profile:
:return: The formatted profile string in format (index) name (comment) <email>
"""
return f"({self.get_profile_number(profile)}) {profile}" return f"({self.get_profile_number(profile)}) {profile}"
def _get_git_subcommand(self, *params): def _get_git_subcommand(self, *params):
"""
Get the git subcommand for a given set of parameters
:param params: The parameters to pass to the git command
:return: The git command string
"""
git_command = "git config" git_command = "git config"
if self.use_global_git_config: if self.use_global_git_config:
git_command += " --global" git_command += " --global"
return f"{git_command} {' '.join(params)}" return f"{git_command} {' '.join(params)}"
def use(self, name_or_email): def use(self, name_or_email):
"""
Use a profile, by applying the name and email to the git config
:param name_or_email: The name or email of the profile to use
:return: None
"""
if profile := self.match_query_to_profile(name_or_email): if profile := self.match_query_to_profile(name_or_email):
print(f"Using profile {self.get_profile_format(profile)}", end=" ") print(f"Using profile {self.get_profile_format(profile)}", end=" ")
try: try:
...@@ -243,6 +306,11 @@ class GPM: ...@@ -243,6 +306,11 @@ class GPM:
print(f"{colorama.Fore.RED}No matching profile found for '{name_or_email}'{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}No matching profile found for '{name_or_email}'{colorama.Style.RESET_ALL}")
def remove(self, name): def remove(self, name):
"""
Remove a profile
:param name: The name or email of the profile to remove
:return: None
"""
if profile := self.match_query_to_profile(name): if profile := self.match_query_to_profile(name):
out_text = f"{colorama.Fore.GREEN}Removed profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}" out_text = f"{colorama.Fore.GREEN}Removed profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}"
self.profiles.remove(profile) self.profiles.remove(profile)
...@@ -252,6 +320,10 @@ class GPM: ...@@ -252,6 +320,10 @@ class GPM:
print(f"{colorama.Fore.RED}No matching profile found for '{name}'{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}No matching profile found for '{name}'{colorama.Style.RESET_ALL}")
def load_git_profile(self) -> Optional[Profile]: def load_git_profile(self) -> Optional[Profile]:
"""
Load the git profile from the git config
:return: The git profile
"""
name = os.popen(self._get_git_subcommand("user.name")).read().strip() name = os.popen(self._get_git_subcommand("user.name")).read().strip()
email = os.popen(self._get_git_subcommand("user.email")).read().strip() email = os.popen(self._get_git_subcommand("user.email")).read().strip()
try: try:
...@@ -261,6 +333,10 @@ class GPM: ...@@ -261,6 +333,10 @@ class GPM:
return Profile(name or "", email or "") return Profile(name or "", email or "")
def _get_local_profile_or_create(self) -> Optional[Profile]: def _get_local_profile_or_create(self) -> Optional[Profile]:
"""
Get the local profile or create a new one
:return: The local profile
"""
profile = self.load_git_profile() profile = self.load_git_profile()
if not profile: if not profile:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
...@@ -280,6 +356,10 @@ class GPM: ...@@ -280,6 +356,10 @@ class GPM:
return profile return profile
def current_show(self): def current_show(self):
"""
Show the current profile
:return: None
"""
profile = self._get_local_profile_or_create() profile = self._get_local_profile_or_create()
if not profile: if not profile:
return return
...@@ -294,12 +374,24 @@ class GPM: ...@@ -294,12 +374,24 @@ class GPM:
sys.exit(1) sys.exit(1)
def get_profile_number(self, profile: Profile) -> int: def get_profile_number(self, profile: Profile) -> int:
"""
Returns the profile number for a given profile if it exists, otherwise -1
:param profile:
:return: The profile number for a given profile if it exists, otherwise -1
"""
for index, prf in enumerate(self.profiles, start=1): for index, prf in enumerate(self.profiles, start=1):
if prf.email == profile.email: if prf.email == profile.email:
return index return index
return -1 return -1
def current_edit(self, name=None, email=None, comment=None): def current_edit(self, name=None, email=None, comment=None):
"""
Edit the current profile
:param name: If provided, the new name for the profile
:param email: If provided, the new email for the profile
:param comment: If provided, the new comment for the profile
:return: None
"""
local_profile = self._get_local_profile_or_create() local_profile = self._get_local_profile_or_create()
self._validate_name_email(local_profile.email, local_profile.name) self._validate_name_email(local_profile.email, local_profile.name)
profile = self._validate_query_profile_or_exit(local_profile.email) profile = self._validate_query_profile_or_exit(local_profile.email)
...@@ -314,11 +406,21 @@ class GPM: ...@@ -314,11 +406,21 @@ class GPM:
@staticmethod @staticmethod
def _validate_name_email(email, name): def _validate_name_email(email, name):
"""
Validate the name and email, exits if both are empty
:param email: The email to validate
:param name: The name to validate
:return: None
"""
if not name and not email: if not name and not email:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
sys.exit(1) sys.exit(1)
def current_remove(self): def current_remove(self):
"""
Remove the current profile from the list of profiles if it exists
:return: None
"""
local_profile = self.load_git_profile() local_profile = self.load_git_profile()
if not local_profile: if not local_profile:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
...@@ -331,12 +433,24 @@ class GPM: ...@@ -331,12 +433,24 @@ class GPM:
print(out_text) print(out_text)
def _validate_query_profile_or_exit(self, email): def _validate_query_profile_or_exit(self, email):
"""
Validate the query profile or exit if it does not exist
:param email: The email to validate
:return: The profile if it exists, otherwise exits
"""
if not (profile := self.match_query_to_profile(email)): if not (profile := self.match_query_to_profile(email)):
print(f"{colorama.Fore.RED}No matching profile found for current git config{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.RED}No matching profile found for current git config{colorama.Style.RESET_ALL}")
sys.exit(1) sys.exit(1)
return profile return profile
def current_import(self, name=None, email=None, comment=None): def current_import(self, name=None, email=None, comment=None):
"""
Import the current profile from the git config
:param name: If provided, the new name for the profile
:param email: If provided, the new email for the profile
:param comment: If provided, the new comment for the profile
:return: None
"""
profile = self.load_git_profile() profile = self.load_git_profile()
if not profile: if not profile:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
...@@ -364,6 +478,10 @@ class GPM: ...@@ -364,6 +478,10 @@ class GPM:
print(f"{colorama.Fore.GREEN}Imported profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.GREEN}Imported profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}")
def run(self): def run(self):
"""
Run the Git Profile Manager
:return: None
"""
parser = setup() parser = setup()
args = parser.parse_args() args = parser.parse_args()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment