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

feat: improvements to 'current' subcommand

parent 575bb9c6
No related branches found
No related tags found
No related merge requests found
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
</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 afterPath="$PROJECT_DIR$/Makefile" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" /> <change beforePath="$PROJECT_DIR$/dist/gpm-0.1.0-py3-none-any.whl" beforeDir="false" afterPath="$PROJECT_DIR$/dist/gpm-0.1.0-py3-none-any.whl" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dist/gpm-0.1.0.tar.gz" beforeDir="false" afterPath="$PROJECT_DIR$/dist/gpm-0.1.0.tar.gz" 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" />
...@@ -16,9 +19,9 @@ ...@@ -16,9 +19,9 @@
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="ProjectColorInfo"><![CDATA[{ <component name="ProjectColorInfo">{
"associatedIndex": 3 &quot;associatedIndex&quot;: 3
}]]></component> }</component>
<component name="ProjectId" id="2kukHjWcYXmjT4aj9YqptoEckn4" /> <component name="ProjectId" id="2kukHjWcYXmjT4aj9YqptoEckn4" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true"> <component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" /> <ConfirmationsSetting value="2" id="Add" />
...@@ -29,9 +32,10 @@ ...@@ -29,9 +32,10 @@
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent"><![CDATA[{
"keyToString": { "keyToString": {
"Makefile Target.build.executor": "Run",
"RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true",
"git-widget-placeholder": "main", "git-widget-placeholder": "main",
"last_opened_file_path": "/Users/leo/School/IDATA1004/GitProfileManager", "last_opened_file_path": "/Users/leo/School/IDATA1004/GPM",
"node.js.detected.package.eslint": "true", "node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true", "node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)", "node.js.selected.package.eslint": "(autodetect)",
...@@ -53,6 +57,19 @@ ...@@ -53,6 +57,19 @@
<recent name="$PROJECT_DIR$/gpm" /> <recent name="$PROJECT_DIR$/gpm" />
</key> </key>
</component> </component>
<component name="RunManager">
<configuration name="build" type="MAKEFILE_TARGET_RUN_CONFIGURATION" factoryName="Makefile" temporary="true">
<makefile filename="$PROJECT_DIR$/Makefile" target="build" workingDirectory="" arguments="">
<envs />
</makefile>
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Makefile Target.build" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes"> <component name="SharedIndexes">
<attachedChunks> <attachedChunks>
<set> <set>
...@@ -70,6 +87,7 @@ ...@@ -70,6 +87,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="3409000" />
</task> </task>
<servers /> <servers />
</component> </component>
......
# Build using poetry
build:
poetry build
# After
install:
pipx install dist/gpm-0.1.0-py3-none-any.whl --force
\ No newline at end of file
No preview for this file type
No preview for this file type
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
GPM - Git Profile Management CLI Git Profile Management CLI
Usage: usage: gpm [-h] [--version] [--author] {add,edit,list,use,remove,current} ...
gpm add <name> <email>
gpm list options:
gpm use <name> -h, --help show help message and exit
gpm remove <name> --version show program's version number and exit
gpm (-h | --help) --author Show author information
gpm --version
Commands:
{add,edit,list,use,remove,current}
add Add a new git profile
edit Edit an existing git profile
list List all git profiles
use Use a git profile
remove Remove a git profile
current Manage the current profile
""" """
__VERSION__ = "0.1.0" __VERSION__ = "0.1.0"
...@@ -88,12 +96,12 @@ def setup(): ...@@ -88,12 +96,12 @@ def setup():
# Current profile subcommand # Current profile subcommand
current_parser = subparsers.add_parser('current', help='Manage the current profile') current_parser = subparsers.add_parser('current', help='Manage the current profile')
current_subparser = current_parser.add_subparsers(title="Commands", dest="current_command") current_subparser = current_parser.add_subparsers(title="Commands", dest="current_command")
current_show_parser = current_subparser.add_parser('show', help='Show the current profile') current_subparser.add_parser('show', help='Show the current profile')
current_edit_parser = current_subparser.add_parser('edit', help='Edit the current profile') current_edit_parser = current_subparser.add_parser('edit', help='Edit the current profile')
current_edit_parser.add_argument('--name', type=str, help='New name for the current profile') current_edit_parser.add_argument('--name', type=str, help='New name for the current profile')
current_edit_parser.add_argument('--email', type=str, help='New email for the current profile') current_edit_parser.add_argument('--email', type=str, help='New email for the current profile')
current_edit_parser.add_argument('--comment', type=str, help='New comment for the current profile') current_edit_parser.add_argument('--comment', type=str, help='New comment for the current profile')
current_remove_parser = current_subparser.add_parser('remove', help='Remove the current profile') current_subparser.add_parser('remove', help='Remove the current profile')
return parser return parser
...@@ -106,8 +114,11 @@ class Profile: ...@@ -106,8 +114,11 @@ class Profile:
def __str__(self): def __str__(self):
if self.comment: if self.comment:
return f"{colorama.Fore.CYAN}{self.name}{colorama.Style.RESET_ALL} {colorama.Fore.YELLOW}({self.comment}){colorama.Style.RESET_ALL} <{colorama.Fore.CYAN}{self.email}{colorama.Style.RESET_ALL}>" return f"{colorama.Fore.CYAN}{self.name or 'Not set'}{colorama.Style.RESET_ALL} {colorama.Fore.YELLOW}({self.comment}){colorama.Style.RESET_ALL} <{colorama.Fore.CYAN}{self.email or 'Not set'}{colorama.Style.RESET_ALL}>"
return f"{colorama.Fore.CYAN}{self.name}{colorama.Style.RESET_ALL} <{colorama.Fore.CYAN}{self.email}{colorama.Style.RESET_ALL}>" return f"{colorama.Fore.CYAN}{self.name or 'Not set'}{colorama.Style.RESET_ALL} <{colorama.Fore.CYAN}{self.email or 'Not set'}{colorama.Style.RESET_ALL}>"
def validate(self):
return re.match(r"[^@]+@[^@]+\.[^@]+", self.email) and bool(self.name)
class GPM: class GPM:
...@@ -144,7 +155,7 @@ class GPM: ...@@ -144,7 +155,7 @@ class GPM:
self.profiles.append(profile) self.profiles.append(profile)
self._save() self._save()
#print(f"Added profile: {name} <{email}>") #print(f"Added profile: {name} <{email}>")
print(f"{colorama.Fore.GREEN}Added profile: {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):
if not name and not email and not comment: if not name and not email and not comment:
...@@ -160,7 +171,7 @@ class GPM: ...@@ -160,7 +171,7 @@ class GPM:
if comment: if comment:
profile.comment = comment profile.comment = comment
self._save() self._save()
print(f"{colorama.Fore.GREEN}Edited profile: {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):
if not self.profiles: if not self.profiles:
...@@ -171,6 +182,11 @@ class GPM: ...@@ -171,6 +182,11 @@ class GPM:
def match_query_to_profile(self, query: str): def match_query_to_profile(self, query: str):
if query.isdigit():
index = int(query) - 1
if index < 0 or index >= len(self.profiles):
return None
return self.profiles[index]
profile_names = [profile.name for profile in self.profiles] profile_names = [profile.name for profile in self.profiles]
profile_emails = [profile.email for profile in self.profiles] profile_emails = [profile.email for profile in self.profiles]
best_name_match = find_best_match(query, profile_names) best_name_match = find_best_match(query, profile_names)
...@@ -191,9 +207,12 @@ class GPM: ...@@ -191,9 +207,12 @@ class GPM:
return None return None
return profile return profile
def get_profile_format(self, profile: Profile):
return f"({self.get_profile_number(profile)}) {profile}"
def use(self, name_or_email): def use(self, name_or_email):
if profile := self.match_query_to_profile(name_or_email): if profile := self.match_query_to_profile(name_or_email):
print(f"Using profile {profile}", end=" ") print(f"Using profile {self.get_profile_format(profile)}", end=" ")
try: try:
os.system(f"git config user.name \"{profile.name}\"") os.system(f"git config user.name \"{profile.name}\"")
os.system(f"git config user.email \"{profile.email}\"") os.system(f"git config user.email \"{profile.email}\"")
...@@ -205,41 +224,66 @@ class GPM: ...@@ -205,41 +224,66 @@ class GPM:
def remove(self, name): def remove(self, name):
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}"
self.profiles.remove(profile) self.profiles.remove(profile)
self._save() self._save()
print(f"{colorama.Fore.GREEN}Removed profile: {profile}{colorama.Style.RESET_ALL}") print(out_text)
else: else:
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 current_show(self): @staticmethod
def load_git_profile() -> Optional[Profile]:
name = os.popen("git config user.name").read().strip() name = os.popen("git config user.name").read().strip()
email = os.popen("git config user.email").read().strip() email = os.popen("git config user.email").read().strip()
if not name and not email: try:
profile = Profile(name, email)
return profile
except TypeError:
return Profile(name or "", email or "")
def _get_local_profile_or_create(self) -> Optional[Profile]:
profile = self.load_git_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}")
else: return None
matching_profiles = [profile for profile in self.profiles if profile.email == email] if not profile.validate():
print(f"{colorama.Fore.YELLOW}Invalid git config{colorama.Style.RESET_ALL}")
print(profile)
sys.exit(1)
if not any(prf.email == profile.email for prf in self.profiles):
print(f"{colorama.Fore.YELLOW}Current git profile is not stored{colorama.Style.RESET_ALL}")
print(profile)
print("Do you want to add it to the list of profiles? (y/n)")
answer = input().strip().lower()
if answer == 'y':
self.add(profile.name, profile.email)
return None
return profile
def current_show(self):
profile = self._get_local_profile_or_create()
if not profile:
return
matching_profiles = [(prf, index) for index, prf in enumerate(self.profiles, start=1) if prf.email == profile.email]
if matching_profiles: if matching_profiles:
print(f"Current profile: {matching_profiles[0]}") print(f"Current profile: {self.get_profile_format(matching_profiles[0][0])}")
if matching_profiles[0].name != name: if matching_profiles[0][0].name != profile.name:
print(f"{colorama.Fore.YELLOW}Warning: Name in git config does not match current profile{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}Warning: Name in git config does not match current profile{colorama.Style.RESET_ALL}")
else: else:
print(f"{colorama.Fore.YELLOW}No matching profile found for current git config{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.YELLOW}No matching profile found for current git config{colorama.Style.RESET_ALL}")
print(f" Name: {name}") print(profile)
print(f" Email: {email}")
sys.exit(1) sys.exit(1)
def get_profile_number(self, profile: Profile) -> int:
for index, prf in enumerate(self.profiles, start=1):
if prf.email == profile.email:
return index
return -1
def current_edit(self, name=None, email=None, comment=None): def current_edit(self, name=None, email=None, comment=None):
if not name and not email and not comment: local_profile = self._get_local_profile_or_create()
print(f"{colorama.Fore.RED}Nothing to edit{colorama.Style.RESET_ALL}") self._validate_name_email(local_profile.email, local_profile.name)
return profile = self._validate_query_profile_or_exit(local_profile.email)
name = name or os.popen("git config user.name").read().strip()
email = email or os.popen("git config user.email").read().strip()
if not name and not email:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
sys.exit(1)
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}")
sys.exit(1)
if name: if name:
profile.name = name profile.name = name
if email: if email:
...@@ -247,20 +291,31 @@ class GPM: ...@@ -247,20 +291,31 @@ class GPM:
if comment: if comment:
profile.comment = comment profile.comment = comment
self._save() self._save()
print(f"{colorama.Fore.GREEN}Edited profile: {profile}{colorama.Style.RESET_ALL}") print(f"{colorama.Fore.GREEN}Edited profile: {self.get_profile_format(profile)}{colorama.Style.RESET_ALL}")
def current_remove(self): @staticmethod
name = os.popen("git config user.name").read().strip() def _validate_name_email(email, name):
email = os.popen("git config user.email").read().strip()
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)
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}") def current_remove(self):
local_profile = self.load_git_profile()
if not local_profile:
print(f"{colorama.Fore.YELLOW}No current profile set{colorama.Style.RESET_ALL}")
sys.exit(1) sys.exit(1)
self._validate_name_email(local_profile.email, local_profile.name)
profile = self._validate_query_profile_or_exit(local_profile.email)
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)
self._save() self._save()
print(f"{colorama.Fore.GREEN}Removed profile: {profile}{colorama.Style.RESET_ALL}") print(out_text)
def _validate_query_profile_or_exit(self, 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}")
sys.exit(1)
return profile
def run(self): def run(self):
parser = setup() parser = setup()
...@@ -288,6 +343,7 @@ class GPM: ...@@ -288,6 +343,7 @@ class GPM:
else: else:
parser.print_help() parser.print_help()
def main(): def main():
gpm = GPM() gpm = GPM()
try: try:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment