pygitgo 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygitgo/__init__.py +0 -0
- pygitgo/auth/__init__.py +0 -0
- pygitgo/auth/account.py +61 -0
- pygitgo/auth/manager.py +78 -0
- pygitgo/auth/ssh_utils.py +114 -0
- pygitgo/commands/__init__.py +0 -0
- pygitgo/commands/git_operations.py +148 -0
- pygitgo/commands/state.py +193 -0
- pygitgo/main.py +283 -0
- pygitgo/utils/__init__.py +0 -0
- pygitgo/utils/colors.py +22 -0
- pygitgo/utils/executor.py +71 -0
- pygitgo/utils/platform_utils.py +170 -0
- pygitgo-1.0.0.dist-info/METADATA +231 -0
- pygitgo-1.0.0.dist-info/RECORD +19 -0
- pygitgo-1.0.0.dist-info/WHEEL +5 -0
- pygitgo-1.0.0.dist-info/entry_points.txt +2 -0
- pygitgo-1.0.0.dist-info/licenses/LICENSE +621 -0
- pygitgo-1.0.0.dist-info/top_level.txt +1 -0
pygitgo/__init__.py
ADDED
|
File without changes
|
pygitgo/auth/__init__.py
ADDED
|
File without changes
|
pygitgo/auth/account.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from pygitgo.utils.executor import run_command
|
|
2
|
+
from pygitgo.utils.colors import info, success, warning, error, BLUE, RESET
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_user():
|
|
7
|
+
try:
|
|
8
|
+
name = run_command(["git", "config", "--global", "user.name"], allow_fail=True)
|
|
9
|
+
email = run_command(["git", "config", "--global", "user.email"], allow_fail=True)
|
|
10
|
+
|
|
11
|
+
if not name or isinstance(name, subprocess.CalledProcessError):
|
|
12
|
+
name = None
|
|
13
|
+
if not email or isinstance(email, subprocess.CalledProcessError):
|
|
14
|
+
email = None
|
|
15
|
+
return name, email
|
|
16
|
+
except:
|
|
17
|
+
return None, None
|
|
18
|
+
|
|
19
|
+
def set_user(name, email):
|
|
20
|
+
run_command(["git", "config", "--global", "user.name", name])
|
|
21
|
+
run_command(["git", "config", "--global", "user.email", email])
|
|
22
|
+
success(f"\nGit user configured Successfully")
|
|
23
|
+
print(f"{BLUE}Username{RESET} : {name}")
|
|
24
|
+
print(f"{BLUE}Email {RESET}: {email}")
|
|
25
|
+
|
|
26
|
+
def ensure_user_configure(default_email=None, default_username=None):
|
|
27
|
+
|
|
28
|
+
name, email = get_user()
|
|
29
|
+
|
|
30
|
+
if name and email:
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
if default_username and default_email:
|
|
34
|
+
info(f"\nConfiguring Git identity from GitHub...")
|
|
35
|
+
set_user(default_username, default_email)
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
warning("\nGit user identity is not configured!")
|
|
39
|
+
info("This is required for your commits to be attributed correctly.")
|
|
40
|
+
|
|
41
|
+
if default_username:
|
|
42
|
+
new_username = default_username
|
|
43
|
+
info(f"Using GitHub username: {new_username}")
|
|
44
|
+
else:
|
|
45
|
+
new_username = input("Enter your Username (for commits): ").strip()
|
|
46
|
+
|
|
47
|
+
prompt_email = "Enter your Email (for commits)"
|
|
48
|
+
if default_email:
|
|
49
|
+
prompt_email += f" [{default_email}]"
|
|
50
|
+
|
|
51
|
+
new_email = input(f"{prompt_email}: ").strip()
|
|
52
|
+
|
|
53
|
+
if not new_email and default_email:
|
|
54
|
+
new_email = default_email
|
|
55
|
+
|
|
56
|
+
if new_username and new_email:
|
|
57
|
+
set_user(new_username, new_email)
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
error("Invalid configuration. Name and Email are required.")
|
|
61
|
+
return False
|
pygitgo/auth/manager.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from pygitgo.utils.executor import run_command
|
|
2
|
+
from pygitgo.utils.colors import info, success, warning, error
|
|
3
|
+
from . import ssh_utils
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
def login():
|
|
7
|
+
if ssh_utils.check_connection():
|
|
8
|
+
success("You are already logged in!")
|
|
9
|
+
return True
|
|
10
|
+
|
|
11
|
+
info("initiating login sequence...")
|
|
12
|
+
|
|
13
|
+
while True:
|
|
14
|
+
email = input("Enter your email for GitHub: ").strip()
|
|
15
|
+
if "@" in email and "." in email:
|
|
16
|
+
break
|
|
17
|
+
else:
|
|
18
|
+
error("Please enter a valid email address.")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
key_path = ssh_utils.generate_ssh_key(email=email)
|
|
22
|
+
pub_key_path = str(key_path) + ".pub"
|
|
23
|
+
|
|
24
|
+
with open(pub_key_path, 'r') as f:
|
|
25
|
+
pub_key = f.read()
|
|
26
|
+
|
|
27
|
+
if pub_key:
|
|
28
|
+
success("SSH Key generated successfully!")
|
|
29
|
+
|
|
30
|
+
print("\n" + "=" * len(pub_key))
|
|
31
|
+
print(pub_key, end='')
|
|
32
|
+
print("=" * len(pub_key) + "\n")
|
|
33
|
+
|
|
34
|
+
info("Copy the key above (between the lines).")
|
|
35
|
+
|
|
36
|
+
input(
|
|
37
|
+
"\nPress Enter to open your GitHub SSH key settings page in the browser...\n"
|
|
38
|
+
"Make sure you are logged in so you can add your new key. "
|
|
39
|
+
"After adding, return here to continue."
|
|
40
|
+
)
|
|
41
|
+
ssh_utils.open_github_settings()
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
error("Failed to read the generated public key.")
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
input("\nPress Enter after adding the key to GitHub...")
|
|
48
|
+
|
|
49
|
+
if ssh_utils.check_connection():
|
|
50
|
+
from .account import ensure_user_configure
|
|
51
|
+
|
|
52
|
+
github_username = ssh_utils.get_github_username()
|
|
53
|
+
|
|
54
|
+
ensure_user_configure(default_email=email, default_username=github_username)
|
|
55
|
+
|
|
56
|
+
success("\nLogin Successful! You are connected.\n")
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
error("Login Failed. Please try again.")
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
def logout():
|
|
63
|
+
key_path = ssh_utils.get_ssh_key_path()
|
|
64
|
+
if not key_path.exists():
|
|
65
|
+
warning("You are already logged out (no keys found).")
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
run_command(["git", "config", "--global", "--unset-all", "user.name"], allow_fail=True)
|
|
70
|
+
run_command(["git", "config", "--global", "--unset-all", "user.email"], allow_fail=True)
|
|
71
|
+
|
|
72
|
+
os.remove(key_path)
|
|
73
|
+
os.remove(str(key_path) + '.pub')
|
|
74
|
+
success("User successfully logout")
|
|
75
|
+
return True
|
|
76
|
+
except Exception as e:
|
|
77
|
+
error(f"Failed to remove SSH keys\nCAUSE OF ERROR: {e}")
|
|
78
|
+
return False
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from pygitgo.utils.executor import run_command
|
|
2
|
+
from pygitgo.utils.colors import info, success, warning, error
|
|
3
|
+
from pygitgo.utils import platform_utils
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def ensure_github_known_host():
|
|
11
|
+
known_hosts = Path.home() / ".ssh" / "known_hosts"
|
|
12
|
+
known_hosts.parent.mkdir(parents=True, exist_ok=True)
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
if known_hosts.exists():
|
|
16
|
+
with open(known_hosts, "r") as f:
|
|
17
|
+
if "github.com" in f.read():
|
|
18
|
+
return
|
|
19
|
+
except Exception:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
info("Adding GitHub to known_hosts...")
|
|
23
|
+
result = run_command(["ssh-keyscan", "-H", "github.com"], allow_fail=True, return_complete=True)
|
|
24
|
+
|
|
25
|
+
if not isinstance(result, Exception) and result.stdout and "github.com" in result.stdout:
|
|
26
|
+
with open(known_hosts, "a") as f:
|
|
27
|
+
f.write(result.stdout)
|
|
28
|
+
if not result.stdout.endswith("\n"):
|
|
29
|
+
f.write("\n")
|
|
30
|
+
success("GitHub added to known_hosts.")
|
|
31
|
+
else:
|
|
32
|
+
warning("Could not automatically add GitHub to known_hosts. You might be prompted.")
|
|
33
|
+
|
|
34
|
+
def check_connection():
|
|
35
|
+
ensure_github_known_host()
|
|
36
|
+
result = run_command(["ssh", "-T", "git@github.com"], allow_fail=True, return_complete=True)
|
|
37
|
+
return "successfully authenticated" in result.stderr
|
|
38
|
+
|
|
39
|
+
def get_github_username():
|
|
40
|
+
|
|
41
|
+
result = run_command(["ssh", "-T", "git@github.com"], allow_fail=True, return_complete=True)
|
|
42
|
+
output = result.stderr
|
|
43
|
+
|
|
44
|
+
if "Hi " in output and "!" in output:
|
|
45
|
+
try:
|
|
46
|
+
username = output.split("Hi ")[1].split("!")[0]
|
|
47
|
+
return username
|
|
48
|
+
except:
|
|
49
|
+
return None
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
def get_ssh_key_path():
|
|
53
|
+
return Path.home() / ".ssh" / "id_ed25519"
|
|
54
|
+
|
|
55
|
+
def generate_ssh_key(email):
|
|
56
|
+
if not email or "@" not in email or "." not in email:
|
|
57
|
+
error("Invalid email address provided for SSH key generation.")
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
key_path = get_ssh_key_path()
|
|
61
|
+
if not key_path.parent.exists():
|
|
62
|
+
key_path.parent.mkdir(parents=True)
|
|
63
|
+
|
|
64
|
+
if key_path.exists():
|
|
65
|
+
os.remove(key_path)
|
|
66
|
+
if (key_path.parent / f"{key_path.name}.pub").exists():
|
|
67
|
+
os.remove(key_path.parent / f"{key_path.name}.pub")
|
|
68
|
+
|
|
69
|
+
command = [
|
|
70
|
+
"ssh-keygen",
|
|
71
|
+
"-t", "ed25519",
|
|
72
|
+
"-C", email,
|
|
73
|
+
"-f", str(key_path),
|
|
74
|
+
"-N", ""
|
|
75
|
+
]
|
|
76
|
+
run_command(command=command)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
run_command(["ssh-add", str(key_path)], allow_fail=True)
|
|
80
|
+
except:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
return key_path
|
|
84
|
+
|
|
85
|
+
def open_github_settings():
|
|
86
|
+
url = "https://github.com/settings/ssh/new"
|
|
87
|
+
if platform_utils.is_windows():
|
|
88
|
+
os.system(f"start {url}")
|
|
89
|
+
elif platform_utils.is_termux():
|
|
90
|
+
os.system(f"termux-open {url}")
|
|
91
|
+
elif platform_utils.is_linux() or platform_utils.is_macos():
|
|
92
|
+
os.system(f"xdg-open {url}")
|
|
93
|
+
else:
|
|
94
|
+
import webbrowser
|
|
95
|
+
webbrowser.open(url)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def convert_https_to_ssh(url):
|
|
99
|
+
|
|
100
|
+
import re
|
|
101
|
+
|
|
102
|
+
pattern = r'^https?://github\.com/([^/]+)/([^/]+?)(?:\.git)?/?$'
|
|
103
|
+
match = re.match(pattern, url.strip())
|
|
104
|
+
|
|
105
|
+
if match:
|
|
106
|
+
owner = match.group(1)
|
|
107
|
+
repo = match.group(2)
|
|
108
|
+
return f"git@github.com:{owner}/{repo}.git"
|
|
109
|
+
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def is_ssh_url(url):
|
|
114
|
+
return url.strip().startswith("git@")
|
|
File without changes
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from pygitgo.auth.ssh_utils import convert_https_to_ssh, is_ssh_url, check_connection
|
|
2
|
+
from pygitgo.utils.executor import run_command
|
|
3
|
+
from pygitgo.utils.colors import info, success, warning, error
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
DEFAULT_MAIN_BRANCH = "main"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_current_branch():
|
|
12
|
+
branch = run_command(["git", "branch", "--show-current"])
|
|
13
|
+
if branch.strip() == "":
|
|
14
|
+
branch = git_new_branch(DEFAULT_MAIN_BRANCH)
|
|
15
|
+
|
|
16
|
+
return branch
|
|
17
|
+
|
|
18
|
+
def is_branch_exist(branch):
|
|
19
|
+
return bool(run_command(["git", "branch", "-r", "--list", f"*/{branch}"])) or bool(run_command(["git", "branch", "--list", branch]))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def git_new_branch(branch):
|
|
23
|
+
run_command(["git", "checkout", "-b", branch], loading_msg=f"Creating branch '{branch}'...")
|
|
24
|
+
success(f"\nBranch '{branch}' created.\n")
|
|
25
|
+
|
|
26
|
+
return branch
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def git_commit(commit_message):
|
|
30
|
+
status_result = run_command(["git", "status", "--porcelain"], allow_fail=True)
|
|
31
|
+
if isinstance(status_result, subprocess.CalledProcessError) or not status_result.strip():
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
run_command(["git", "add", "."], loading_msg="Staging files...")
|
|
35
|
+
clean_message = commit_message.strip('"\'')
|
|
36
|
+
|
|
37
|
+
run_command(["git", "commit", "-m", clean_message], loading_msg="Committing changes...")
|
|
38
|
+
|
|
39
|
+
return True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def git_init():
|
|
43
|
+
if os.path.isdir(".git"):
|
|
44
|
+
warning("Already a git repository! Skipping init...")
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
result = run_command(["git", "init", "-b", DEFAULT_MAIN_BRANCH], allow_fail=True, loading_msg="Initializing git repository...")
|
|
48
|
+
if isinstance(result, subprocess.CalledProcessError):
|
|
49
|
+
run_command(["git", "init"], loading_msg="Initializing git repository...")
|
|
50
|
+
run_command(["git", "checkout", "-b", DEFAULT_MAIN_BRANCH], allow_fail=True)
|
|
51
|
+
|
|
52
|
+
success("Git repository initialized.")
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def add_remote_origin(repo_url):
|
|
57
|
+
clean_url = repo_url.strip('"\'')
|
|
58
|
+
|
|
59
|
+
existing_remote = run_command(["git", "remote", "get-url", "origin"], allow_fail=True)
|
|
60
|
+
if not isinstance(existing_remote, subprocess.CalledProcessError):
|
|
61
|
+
warning(f"Remote origin already exists: {existing_remote}")
|
|
62
|
+
run_command(["git", "remote", "set-url", "origin", clean_url], loading_msg="Updating remote URL...")
|
|
63
|
+
else:
|
|
64
|
+
run_command(["git", "remote", "add", "origin", clean_url], loading_msg="Adding remote origin...")
|
|
65
|
+
|
|
66
|
+
success(f"Remote origin set to: {clean_url}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def confirm_remote_link():
|
|
70
|
+
test_result = run_command(["git", "ls-remote", "origin"], allow_fail=True, loading_msg="Testing connection to remote...")
|
|
71
|
+
|
|
72
|
+
if isinstance(test_result, subprocess.CalledProcessError):
|
|
73
|
+
error("Failed to connect to remote repository!")
|
|
74
|
+
warning("Please check your repository URL and network connection.")
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
success("Successfully connected to remote repository.")
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def create_main_branch():
|
|
82
|
+
current_branch = run_command(["git", "branch", "--show-current"], allow_fail=True)
|
|
83
|
+
|
|
84
|
+
if isinstance(current_branch, subprocess.CalledProcessError) or not current_branch.strip():
|
|
85
|
+
run_command(["git", "checkout", "-b", "main"], loading_msg="Setting default branch to 'main'...")
|
|
86
|
+
elif current_branch.strip() != "main":
|
|
87
|
+
run_command(["git", "branch", "-m", "main"], loading_msg=f"Renaming branch '{current_branch.strip()}' to 'main'...")
|
|
88
|
+
else:
|
|
89
|
+
success("Already on 'main' branch.")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def check_and_sync_branch(branch):
|
|
93
|
+
try:
|
|
94
|
+
run_command(["git", "fetch", "origin"], loading_msg="Checking if branch is up to date...")
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
local_commit = run_command(["git", "rev-parse", branch])
|
|
98
|
+
remote_commit = run_command(["git", "rev-parse", f"origin/{branch}"])
|
|
99
|
+
|
|
100
|
+
if local_commit != remote_commit:
|
|
101
|
+
behind_check = run_command(
|
|
102
|
+
["git", "rev-list", "--count", f"{branch}..origin/{branch}"]
|
|
103
|
+
)
|
|
104
|
+
if behind_check and int(behind_check) > 0:
|
|
105
|
+
warning(f"Local branch is behind remote by {behind_check} commit(s). Pulling changes...")
|
|
106
|
+
output = run_command(["git", "pull", "--rebase", "origin", branch], loading_msg="Pulling changes from remote...")
|
|
107
|
+
if output:
|
|
108
|
+
print(output)
|
|
109
|
+
success("Successfully synced with remote!")
|
|
110
|
+
else:
|
|
111
|
+
success("Branch is up to date or ahead of remote.")
|
|
112
|
+
else:
|
|
113
|
+
success("Branch is already up to date.")
|
|
114
|
+
except:
|
|
115
|
+
warning("Remote branch doesn't exist yet. First push will create it.")
|
|
116
|
+
except:
|
|
117
|
+
warning("Could not fetch from remote. Proceeding with push...")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def git_push(branch):
|
|
121
|
+
remote_url = run_command(["git", "remote", "get-url", "origin"], allow_fail=True)
|
|
122
|
+
|
|
123
|
+
if not isinstance(remote_url, subprocess.CalledProcessError) and remote_url:
|
|
124
|
+
remote_url = remote_url.strip()
|
|
125
|
+
|
|
126
|
+
if not is_ssh_url(remote_url) and check_connection():
|
|
127
|
+
ssh_url = convert_https_to_ssh(remote_url)
|
|
128
|
+
if ssh_url:
|
|
129
|
+
run_command(["git", "remote", "set-url", "origin", ssh_url], loading_msg="Converting remote from HTTPS to SSH for secure push...")
|
|
130
|
+
success(f"Remote updated to: {ssh_url}")
|
|
131
|
+
|
|
132
|
+
run_command(["git", "push", "-u", "origin", branch], loading_msg=f"Pushing to remote branch '{branch}'...")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def handle_rebase():
|
|
136
|
+
status = run_command(["git", "status"], allow_fail=True)
|
|
137
|
+
if isinstance(status, subprocess.CalledProcessError):
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
if "rebase in progress" in status or "rebase" in status.lower():
|
|
141
|
+
warning("\nConflict detected!")
|
|
142
|
+
warning("Please resolve conflicts manually, then run:")
|
|
143
|
+
info(" git add <files>")
|
|
144
|
+
info(" git rebase --continue")
|
|
145
|
+
warning("When finished, run 'gitgo push <branch> <message>' again.\n")
|
|
146
|
+
sys.exit(1)
|
|
147
|
+
|
|
148
|
+
return True
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
from pygitgo.utils.executor import run_command
|
|
2
|
+
from pygitgo.utils.colors import info, highlight, error, warning, success
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def all_save_state():
|
|
7
|
+
output = run_command(["git", "stash", "list", "--pretty=%gd: %s"])
|
|
8
|
+
if not output:
|
|
9
|
+
info("\nNo saved states found.\n")
|
|
10
|
+
sys.exit(0)
|
|
11
|
+
|
|
12
|
+
save_states = [result[6:] for result in output.splitlines()]
|
|
13
|
+
|
|
14
|
+
return save_states
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def display_save_states():
|
|
18
|
+
save_states = all_save_state()
|
|
19
|
+
|
|
20
|
+
print("\nSaved States:")
|
|
21
|
+
print("-" * 32)
|
|
22
|
+
for state in save_states:
|
|
23
|
+
state_index = state.split(': ', 1)[0].replace("stash@", "").replace("{", "").replace("}", "")
|
|
24
|
+
highlight(f"{int(state_index) + 1} | {state.split(': ', 1)[1]}")
|
|
25
|
+
|
|
26
|
+
print("-" * 32 + '\n')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def validate_state_id(state_id, save_states):
|
|
30
|
+
if not state_id.isdigit():
|
|
31
|
+
error("\nInvalid input. Please enter a valid state ID.\n")
|
|
32
|
+
return False
|
|
33
|
+
elif (int(state_id) - 1) < 0:
|
|
34
|
+
error("\nState ID cannot be negative. Please enter a valid state ID.\n")
|
|
35
|
+
return False
|
|
36
|
+
elif (int(state_id) - 1) >= len(save_states):
|
|
37
|
+
error("\nState ID out of range. Please enter a valid state ID.\n")
|
|
38
|
+
return False
|
|
39
|
+
return True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def ask_state_id(save_states):
|
|
43
|
+
proceed = False
|
|
44
|
+
state_id = None
|
|
45
|
+
|
|
46
|
+
while not proceed:
|
|
47
|
+
state_id = input(">> ").strip().lower()
|
|
48
|
+
if state_id == 'q':
|
|
49
|
+
warning("\nLoad operation cancelled by user.\n")
|
|
50
|
+
sys.exit(0)
|
|
51
|
+
proceed = validate_state_id(state_id, save_states)
|
|
52
|
+
|
|
53
|
+
return state_id
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def state_list(arguments):
|
|
57
|
+
if len(arguments) > 1:
|
|
58
|
+
if arguments[1] in ("-h", "--help", "help"):
|
|
59
|
+
print("\nDisplay all saved states.\n")
|
|
60
|
+
warning("\nUsage:\n")
|
|
61
|
+
print(" gitgo state list # Show all saved states")
|
|
62
|
+
print(" gitgo state -l # Alias\n")
|
|
63
|
+
sys.exit(0)
|
|
64
|
+
error("\nToo many arguments for list operation!\n")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
display_save_states()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def load_state(arguments):
|
|
71
|
+
if len(arguments) > 2:
|
|
72
|
+
error("\nToo many arguments for load operation!\n")
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
|
|
75
|
+
save_states = all_save_state()
|
|
76
|
+
proceed = False
|
|
77
|
+
state_id = None
|
|
78
|
+
|
|
79
|
+
if len(arguments) == 2:
|
|
80
|
+
if arguments[1] in ("-h", "--help", "help"):
|
|
81
|
+
print("\nLoad a previously saved working state.\n")
|
|
82
|
+
warning("\nUsage:\n")
|
|
83
|
+
print(" gitgo state load <id> # Load a specific state by ID")
|
|
84
|
+
print(" gitgo state load # Show all saved states and prompt for selection")
|
|
85
|
+
print(" gitgo state -o <id> # Alias\n")
|
|
86
|
+
sys.exit(0)
|
|
87
|
+
elif arguments[1].isdigit():
|
|
88
|
+
state_id = arguments[1]
|
|
89
|
+
proceed = validate_state_id(state_id, save_states)
|
|
90
|
+
if not proceed:
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
else:
|
|
93
|
+
error(f"\nInvalid argument '{arguments[1]}' for load operation. Expected a state ID.\n")
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
|
|
96
|
+
if not proceed:
|
|
97
|
+
display_save_states()
|
|
98
|
+
info("\nEnter the ID of the state you want to load (or 'q' to cancel): ")
|
|
99
|
+
state_id = ask_state_id(save_states)
|
|
100
|
+
|
|
101
|
+
run_command(["git", "stash", "apply", str(int(state_id) - 1)])
|
|
102
|
+
|
|
103
|
+
success(f"\nState '{save_states[int(state_id) - 1]}' loaded successfully.\n")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def save_state(arguments):
|
|
107
|
+
if len(arguments) > 2:
|
|
108
|
+
error("\nToo many arguments for save operation!\n")
|
|
109
|
+
sys.exit(1)
|
|
110
|
+
elif len(arguments) < 2:
|
|
111
|
+
state_name = "Auto-Save"
|
|
112
|
+
|
|
113
|
+
if len(arguments) == 2:
|
|
114
|
+
if arguments[1] in ("-h", "--help", "help"):
|
|
115
|
+
print("\nSave the current working state with an optional name.\n")
|
|
116
|
+
warning("\nUsage:\n")
|
|
117
|
+
print(" gitgo state save <name> # Save with a specific name")
|
|
118
|
+
print(" gitgo state save # Save with default name 'Auto-Save'")
|
|
119
|
+
print(" gitgo state -s <name> # Alias\n")
|
|
120
|
+
sys.exit(0)
|
|
121
|
+
|
|
122
|
+
state_name = arguments[1]
|
|
123
|
+
|
|
124
|
+
run_command(["git", "stash", "push", "-m", state_name])
|
|
125
|
+
|
|
126
|
+
success(f"\nState '{state_name}' saved successfully.\n")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def delete_state(arguments):
|
|
130
|
+
if len(arguments) > 2:
|
|
131
|
+
error("\nToo many arguments for delete operation!\n")
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
elif len(arguments) < 2:
|
|
134
|
+
state_id = ask_state_id(all_save_state())
|
|
135
|
+
else:
|
|
136
|
+
if arguments[1] in ("-h", "--help", "help"):
|
|
137
|
+
print("\nDelete one or all saved working states.\n")
|
|
138
|
+
warning("\nUsage:\n")
|
|
139
|
+
print(" gitgo state delete <id> # Delete a specific state by ID")
|
|
140
|
+
print(" gitgo state delete -a # Delete all saved states")
|
|
141
|
+
print(" gitgo state -d <id> # Alias\n")
|
|
142
|
+
print(" gitgo state -d <id> # Alias for delete all\n")
|
|
143
|
+
sys.exit(0)
|
|
144
|
+
|
|
145
|
+
elif arguments[1] == '-a':
|
|
146
|
+
confirm = input("\nAre you sure you want to delete all saved states? (y/n): ").strip().lower()
|
|
147
|
+
if confirm.lower() == 'y':
|
|
148
|
+
run_command(["git", "stash", "clear"])
|
|
149
|
+
success("\nAll saved states deleted successfully.\n")
|
|
150
|
+
sys.exit(0)
|
|
151
|
+
else:
|
|
152
|
+
warning("\nDelete operation cancelled by user.\n")
|
|
153
|
+
sys.exit(0)
|
|
154
|
+
|
|
155
|
+
elif not arguments[1].isdigit():
|
|
156
|
+
error("\nInvalid input. Please enter a valid state ID.\n")
|
|
157
|
+
sys.exit(1)
|
|
158
|
+
|
|
159
|
+
state_id = arguments[1]
|
|
160
|
+
if not validate_state_id(state_id, all_save_state()):
|
|
161
|
+
sys.exit(1)
|
|
162
|
+
|
|
163
|
+
run_command(["git", "stash", "drop", str(int(state_id) - 1)])
|
|
164
|
+
success(f"\nState with ID '{state_id}' deleted successfully.\n")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def state_operations_help():
|
|
168
|
+
warning("\nState Operations Help:\n")
|
|
169
|
+
print(" list, -l Display all saved states.")
|
|
170
|
+
print(" load, -o Load a previously saved working state.")
|
|
171
|
+
print(" save, -s Save the current working state with a given name.")
|
|
172
|
+
print(" delete, -d Delete a previously saved working state.\n")
|
|
173
|
+
info("Use 'gitgo state <operation> --help' for more information on a specific operation.\n")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def state_operations(arguments):
|
|
177
|
+
if len(arguments) == 0 or arguments[0] in ("-h", "--help", "help"):
|
|
178
|
+
state_operations_help()
|
|
179
|
+
sys.exit(0)
|
|
180
|
+
|
|
181
|
+
type_of_operation = arguments[0].lower()
|
|
182
|
+
if type_of_operation in ["list", "-l"]:
|
|
183
|
+
state_list(arguments)
|
|
184
|
+
elif type_of_operation in ["load", "-o"]:
|
|
185
|
+
load_state(arguments)
|
|
186
|
+
elif type_of_operation in ["save", "-s"]:
|
|
187
|
+
save_state(arguments)
|
|
188
|
+
elif type_of_operation in ["delete", "-d"]:
|
|
189
|
+
delete_state(arguments)
|
|
190
|
+
else:
|
|
191
|
+
error(f"\nUnknown state operation: {type_of_operation}\n")
|
|
192
|
+
state_operations_help()
|
|
193
|
+
sys.exit(1)
|