gitarsenal-cli 1.3.7 ā 1.3.9
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.
- package/package.json +1 -1
- package/python/fixed_function.py +58 -0
- package/python/test_modalSandboxScript.py +467 -134
- package/python/test_modalSandboxScript.py.bak +3672 -0
@@ -119,12 +119,12 @@ except Exception as e:
|
|
119
119
|
# print(f"š Token ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
|
120
120
|
# print(f"š Token secret exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
|
121
121
|
# print(f"š Token exists: {'Yes' if os.environ.get('MODAL_TOKEN') else 'No'}")
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
122
|
+
if os.environ.get('MODAL_TOKEN_ID'):
|
123
|
+
print(f"š Token ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
|
124
|
+
if os.environ.get('MODAL_TOKEN_SECRET'):
|
125
|
+
print(f"š Token secret length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
|
126
|
+
if os.environ.get('MODAL_TOKEN'):
|
127
|
+
print(f"š Token length: {len(os.environ.get('MODAL_TOKEN'))}")
|
128
128
|
# print(f"ā
Token setup completed")
|
129
129
|
|
130
130
|
# Import modal after token setup
|
@@ -2025,7 +2025,7 @@ cd "{current_dir}"
|
|
2025
2025
|
print("ā³ Sandbox will remain running until you terminate it with:")
|
2026
2026
|
print(f"modal sandbox terminate {sandbox_id}")
|
2027
2027
|
|
2028
|
-
# Try to open a new terminal window and connect to the
|
2028
|
+
# Try to open a new terminal window and connect to the container
|
2029
2029
|
if container_id:
|
2030
2030
|
print("š„ļø Attempting to open new terminal window...")
|
2031
2031
|
# Use osascript to open a new terminal with the modal shell command
|
@@ -2558,6 +2558,15 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
2558
2558
|
print(f"ā Error running container: {e}")
|
2559
2559
|
return None
|
2560
2560
|
|
2561
|
+
def is_local_server_running(url, timeout=2):
|
2562
|
+
"""Check if a local server is running by attempting a connection."""
|
2563
|
+
import requests
|
2564
|
+
try:
|
2565
|
+
response = requests.get(url, timeout=timeout)
|
2566
|
+
return True
|
2567
|
+
except requests.exceptions.RequestException:
|
2568
|
+
return False
|
2569
|
+
|
2561
2570
|
def fetch_setup_commands_from_api(repo_url):
|
2562
2571
|
"""Fetch setup commands from the GitIngest API using real repository analysis."""
|
2563
2572
|
import tempfile
|
@@ -2565,8 +2574,13 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2565
2574
|
import os
|
2566
2575
|
import shutil
|
2567
2576
|
import json
|
2577
|
+
import time
|
2578
|
+
import requests
|
2568
2579
|
|
2569
|
-
|
2580
|
+
# Define API endpoints to try in order - using only online endpoints
|
2581
|
+
api_endpoints = [
|
2582
|
+
"https://www.gitarsenal.dev/api/analyze-with-gitingest" # Working endpoint with www prefix
|
2583
|
+
]
|
2570
2584
|
|
2571
2585
|
print(f"š Fetching setup commands from API for repository: {repo_url}")
|
2572
2586
|
|
@@ -2588,6 +2602,13 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2588
2602
|
temp_dir = tempfile.mkdtemp(prefix="repo_analysis_")
|
2589
2603
|
output_file = os.path.join(temp_dir, "digest.json")
|
2590
2604
|
|
2605
|
+
# Create a directory to save GitIngest results
|
2606
|
+
save_dir = os.path.join(os.path.expanduser("~"), "gitarsenal_results")
|
2607
|
+
os.makedirs(save_dir, exist_ok=True)
|
2608
|
+
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
2609
|
+
repo_name = repo_url.split("/")[-1].replace(".git", "")
|
2610
|
+
save_file = os.path.join(save_dir, f"gitingest_{repo_name}_{timestamp}.txt")
|
2611
|
+
|
2591
2612
|
try:
|
2592
2613
|
if has_gitingest_cli:
|
2593
2614
|
# Use gitingest CLI tool to analyze the repository directly from URL
|
@@ -2618,44 +2639,87 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2618
2639
|
else:
|
2619
2640
|
print(f"ā
GitIngest analysis completed successfully")
|
2620
2641
|
|
2621
|
-
# Read the output file -
|
2642
|
+
# Read the output file - note that the default format might not be JSON
|
2622
2643
|
try:
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2647
|
-
|
2648
|
-
|
2649
|
-
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
2658
|
-
|
2644
|
+
# First try to parse as JSON
|
2645
|
+
try:
|
2646
|
+
with open(output_file, 'r', encoding='utf-8') as f:
|
2647
|
+
content = f.read()
|
2648
|
+
|
2649
|
+
# Save the GitIngest output to the results directory
|
2650
|
+
with open(save_file, 'w', encoding='utf-8') as save_f:
|
2651
|
+
save_f.write(content)
|
2652
|
+
print(f"š GitIngest output saved to: {save_file}")
|
2653
|
+
|
2654
|
+
try:
|
2655
|
+
gitingest_data = json.loads(content)
|
2656
|
+
print(f"ā
GitIngest data loaded as JSON from {output_file}")
|
2657
|
+
except json.JSONDecodeError:
|
2658
|
+
# If not JSON, convert the text output to a basic structure
|
2659
|
+
print(f"ā ļø GitIngest output is not in JSON format, converting text to structure")
|
2660
|
+
|
2661
|
+
# Process the text to extract useful information
|
2662
|
+
import re
|
2663
|
+
|
2664
|
+
# Try to identify language
|
2665
|
+
language_match = re.search(r"(?i)language[s]?:?\s*(\w+)", content)
|
2666
|
+
detected_language = language_match.group(1) if language_match else "Unknown"
|
2667
|
+
|
2668
|
+
# Try to identify technologies with stronger evidence requirements
|
2669
|
+
tech_patterns = {
|
2670
|
+
"python": r"(?i)(python|\.py\b|pip\b|requirements\.txt|setup\.py)",
|
2671
|
+
"javascript": r"(?i)(javascript|\.js\b|node|npm|yarn|package\.json)",
|
2672
|
+
"typescript": r"(?i)(typescript|\.ts\b|tsc\b|tsconfig\.json)",
|
2673
|
+
"go": r"(?i)(\bgo\b|golang|\.go\b|go\.mod|go\.sum)",
|
2674
|
+
"rust": r"(?i)(rust|\.rs\b|cargo|Cargo\.toml)",
|
2675
|
+
"java": r"(?i)(java\b|\.java\b|maven|gradle|pom\.xml)",
|
2676
|
+
"c++": r"(?i)(c\+\+|\.cpp\b|\.hpp\b|cmake\b|CMakeLists\.txt)",
|
2677
|
+
"pytorch": r"(?i)(pytorch|torch\b|nn\.Module)",
|
2678
|
+
"tensorflow": r"(?i)(tensorflow|tf\.|keras\b)",
|
2679
|
+
}
|
2680
|
+
|
2681
|
+
# Count occurrences to filter out false positives
|
2682
|
+
tech_counts = {}
|
2683
|
+
for tech, pattern in tech_patterns.items():
|
2684
|
+
matches = re.findall(pattern, content)
|
2685
|
+
if matches:
|
2686
|
+
tech_counts[tech] = len(matches)
|
2687
|
+
|
2688
|
+
# Filter technologies based on threshold
|
2689
|
+
thresholds = {
|
2690
|
+
"javascript": 3, # Higher threshold for JavaScript
|
2691
|
+
"go": 3, # Higher threshold for Go
|
2692
|
+
"default": 2 # Default threshold
|
2693
|
+
}
|
2694
|
+
|
2695
|
+
detected_technologies = []
|
2696
|
+
for tech, count in tech_counts.items():
|
2697
|
+
threshold = thresholds.get(tech, thresholds["default"])
|
2698
|
+
if count >= threshold:
|
2699
|
+
detected_technologies.append(tech)
|
2700
|
+
print(f"š Detected {tech} with confidence score {count}")
|
2701
|
+
|
2702
|
+
# Create a structured representation
|
2703
|
+
gitingest_data = {
|
2704
|
+
"system_info": {
|
2705
|
+
"detected_language": detected_language,
|
2706
|
+
"detected_technologies": detected_technologies,
|
2707
|
+
},
|
2708
|
+
"repository_analysis": {
|
2709
|
+
"summary": content[:5000], # First 5000 chars as summary
|
2710
|
+
"content_preview": content[:10000] # First 10000 chars as preview
|
2711
|
+
},
|
2712
|
+
"success": True
|
2713
|
+
}
|
2714
|
+
|
2715
|
+
# Save the processed data
|
2716
|
+
processed_file = os.path.join(save_dir, f"gitingest_processed_{repo_name}_{timestamp}.json")
|
2717
|
+
with open(processed_file, 'w', encoding='utf-8') as proc_f:
|
2718
|
+
json.dump(gitingest_data, proc_f, indent=2)
|
2719
|
+
print(f"š Processed GitIngest data saved to: {processed_file}")
|
2720
|
+
except FileNotFoundError:
|
2721
|
+
print(f"ā ļø Output file not found at {output_file}")
|
2722
|
+
gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
|
2659
2723
|
except Exception as e:
|
2660
2724
|
print(f"ā ļø Error reading GitIngest output: {e}")
|
2661
2725
|
gitingest_data = generate_basic_repo_analysis_from_url(repo_url)
|
@@ -2672,17 +2736,46 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2672
2736
|
|
2673
2737
|
print(f"š¤ API Request payload prepared (GitIngest data size: {len(json.dumps(gitingest_data))} bytes)")
|
2674
2738
|
|
2675
|
-
#
|
2676
|
-
|
2677
|
-
|
2678
|
-
|
2739
|
+
# Try each endpoint in sequence until one succeeds
|
2740
|
+
response = None
|
2741
|
+
for api_url in api_endpoints:
|
2742
|
+
# Use the retry mechanism for more reliable requests
|
2743
|
+
response = make_api_request_with_retry(
|
2744
|
+
url=api_url,
|
2745
|
+
payload=payload,
|
2746
|
+
max_retries=2,
|
2747
|
+
timeout=180 # 3 minute timeout
|
2748
|
+
)
|
2679
2749
|
|
2750
|
+
# If we got a response and it's successful, break out of the loop
|
2751
|
+
if response and response.status_code == 200:
|
2752
|
+
print(f"ā
Successful response from {api_url}")
|
2753
|
+
break
|
2754
|
+
|
2755
|
+
if response:
|
2756
|
+
print(f"ā ļø Endpoint {api_url} returned status code {response.status_code}, trying next endpoint...")
|
2757
|
+
else:
|
2758
|
+
print(f"ā ļø Failed to connect to {api_url}, trying next endpoint...")
|
2759
|
+
|
2760
|
+
# If we've tried all endpoints and still don't have a response, use fallback
|
2761
|
+
if response is None:
|
2762
|
+
print("ā All API endpoints failed")
|
2763
|
+
return generate_fallback_commands(gitingest_data)
|
2764
|
+
|
2765
|
+
# Continue with the response we got from the successful endpoint
|
2766
|
+
if not response:
|
2767
|
+
print("ā No valid response received from any endpoint")
|
2768
|
+
return generate_fallback_commands(gitingest_data)
|
2769
|
+
|
2770
|
+
try:
|
2680
2771
|
print(f"š„ API Response status code: {response.status_code}")
|
2681
2772
|
|
2682
2773
|
if response.status_code == 200:
|
2683
2774
|
try:
|
2684
2775
|
data = response.json()
|
2685
2776
|
print(f"š API Response data received")
|
2777
|
+
print(f"š Response size: {len(response.text)} bytes")
|
2778
|
+
print(f"š Response URL: {response.url}")
|
2686
2779
|
|
2687
2780
|
# Extract setup commands from the response
|
2688
2781
|
if "setupInstructions" in data and "commands" in data["setupInstructions"]:
|
@@ -2720,68 +2813,40 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2720
2813
|
print("š Available fields in response:")
|
2721
2814
|
for key in data.keys():
|
2722
2815
|
print(f" - {key}")
|
2723
|
-
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2730
|
-
except Exception as e:
|
2731
|
-
print(f"ā ļø Error parsing API response: {e}")
|
2816
|
+
# Return fallback commands
|
2817
|
+
return generate_fallback_commands(gitingest_data)
|
2818
|
+
except json.JSONDecodeError as e:
|
2819
|
+
print(f"ā Failed to parse API response as JSON: {e}")
|
2820
|
+
print(f"Raw response: {response.text[:500]}...")
|
2821
|
+
# Return fallback commands
|
2822
|
+
return generate_fallback_commands(gitingest_data)
|
2732
2823
|
elif response.status_code == 504:
|
2733
2824
|
print(f"ā API request timed out (504 Gateway Timeout)")
|
2734
|
-
print(
|
2735
|
-
|
2736
|
-
|
2737
|
-
print("\n" + "="*80)
|
2738
|
-
print("š GENERATING FALLBACK SETUP COMMANDS")
|
2739
|
-
print("="*80)
|
2740
|
-
fallback_commands = generate_fallback_commands(gitingest_data)
|
2741
|
-
return fallback_commands
|
2825
|
+
print("ā ļø The server took too long to respond. Using fallback commands instead.")
|
2826
|
+
# Return fallback commands
|
2827
|
+
return generate_fallback_commands(gitingest_data)
|
2742
2828
|
else:
|
2743
|
-
print(f"ā API request failed with status code {response.status_code}")
|
2744
|
-
print(f"Response: {response.
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
print("="*80)
|
2750
|
-
fallback_commands = generate_fallback_commands(gitingest_data)
|
2751
|
-
return fallback_commands
|
2752
|
-
except requests.exceptions.Timeout:
|
2753
|
-
print(f"ā API request timed out after 30 seconds")
|
2754
|
-
print(f"ā ļø The server took too long to respond. Using fallback commands instead.")
|
2755
|
-
|
2756
|
-
# Generate fallback commands based on the gitingest data
|
2757
|
-
print("\n" + "="*80)
|
2758
|
-
print("š GENERATING FALLBACK SETUP COMMANDS")
|
2759
|
-
print("="*80)
|
2760
|
-
fallback_commands = generate_fallback_commands(gitingest_data)
|
2761
|
-
return fallback_commands
|
2829
|
+
print(f"ā API request failed with status code: {response.status_code}")
|
2830
|
+
print(f"ā Response URL: {response.url}")
|
2831
|
+
print(f"ā Response headers: {dict(response.headers)}")
|
2832
|
+
print(f"ā Error response: {response.text[:500]}...")
|
2833
|
+
# Return fallback commands
|
2834
|
+
return generate_fallback_commands(gitingest_data)
|
2762
2835
|
except Exception as e:
|
2763
|
-
print(f"ā Error
|
2764
|
-
|
2765
|
-
#
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2836
|
+
print(f"ā Error processing API response: {str(e)}")
|
2837
|
+
print("ā ļø Using fallback commands instead")
|
2838
|
+
# Return fallback commands
|
2839
|
+
return generate_fallback_commands(gitingest_data)
|
2840
|
+
except Exception as e:
|
2841
|
+
print(f"ā Error fetching setup commands from API: {e}")
|
2842
|
+
import traceback
|
2843
|
+
traceback.print_exc()
|
2844
|
+
# Return fallback commands
|
2845
|
+
return generate_fallback_commands(None)
|
2771
2846
|
finally:
|
2772
|
-
# Clean up temporary directory
|
2847
|
+
# Clean up the temporary directory
|
2773
2848
|
print(f"š§¹ Cleaning up temporary directory...")
|
2774
|
-
|
2775
|
-
shutil.rmtree(temp_dir)
|
2776
|
-
except Exception as e:
|
2777
|
-
print(f"ā ļø Error cleaning up temporary directory: {e}")
|
2778
|
-
|
2779
|
-
# If all else fails, return basic setup commands
|
2780
|
-
return [
|
2781
|
-
"apt-get update -y",
|
2782
|
-
"apt-get install -y git curl wget",
|
2783
|
-
"pip install --upgrade pip setuptools wheel"
|
2784
|
-
]
|
2849
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
2785
2850
|
|
2786
2851
|
def generate_fallback_commands(gitingest_data):
|
2787
2852
|
"""Generate fallback setup commands based on repository analysis"""
|
@@ -3060,8 +3125,11 @@ def generate_basic_repo_analysis(repo_dir):
|
|
3060
3125
|
}
|
3061
3126
|
|
3062
3127
|
def get_setup_commands_from_local_api(repo_url, gitingest_data):
|
3063
|
-
"""Try to get setup commands from the
|
3064
|
-
|
3128
|
+
"""Try to get setup commands from the API."""
|
3129
|
+
# Use only online endpoints
|
3130
|
+
api_endpoints = [
|
3131
|
+
"https://www.gitarsenal.dev/api/analyze-with-gitingest" # Working endpoint with www prefix
|
3132
|
+
]
|
3065
3133
|
|
3066
3134
|
# Prepare the request payload
|
3067
3135
|
payload = {
|
@@ -3070,34 +3138,49 @@ def get_setup_commands_from_local_api(repo_url, gitingest_data):
|
|
3070
3138
|
"userRequest": "Setup and run the repository"
|
3071
3139
|
}
|
3072
3140
|
|
3073
|
-
|
3074
|
-
|
3075
|
-
|
3076
|
-
response =
|
3141
|
+
# Try each API endpoint
|
3142
|
+
for api_url in api_endpoints:
|
3143
|
+
# Use the retry mechanism for more reliable requests
|
3144
|
+
response = make_api_request_with_retry(
|
3145
|
+
url=api_url,
|
3146
|
+
payload=payload,
|
3147
|
+
max_retries=2,
|
3148
|
+
timeout=180 # 3 minute timeout
|
3149
|
+
)
|
3077
3150
|
|
3078
|
-
if response.status_code == 200:
|
3079
|
-
|
3080
|
-
|
3081
|
-
|
3082
|
-
print(f"
|
3083
|
-
|
3084
|
-
|
3085
|
-
|
3086
|
-
|
3087
|
-
|
3088
|
-
|
3089
|
-
|
3090
|
-
|
3091
|
-
|
3092
|
-
|
3093
|
-
|
3094
|
-
|
3095
|
-
|
3096
|
-
|
3097
|
-
|
3098
|
-
|
3099
|
-
|
3151
|
+
if response and response.status_code == 200:
|
3152
|
+
try:
|
3153
|
+
data = response.json()
|
3154
|
+
print(f"š Response size: {len(response.text)} bytes")
|
3155
|
+
print(f"š Response URL: {response.url}")
|
3156
|
+
if "setupInstructions" in data and "commands" in data["setupInstructions"]:
|
3157
|
+
commands = data["setupInstructions"]["commands"]
|
3158
|
+
print(f"ā
Successfully fetched {len(commands)} setup commands from API at {api_url}")
|
3159
|
+
|
3160
|
+
# Print the original commands
|
3161
|
+
print("š Original commands from API:")
|
3162
|
+
for i, cmd in enumerate(commands, 1):
|
3163
|
+
print(f" {i}. {cmd}")
|
3164
|
+
|
3165
|
+
# Fix the commands
|
3166
|
+
fixed_commands = fix_setup_commands(commands)
|
3167
|
+
|
3168
|
+
# Print the fixed commands
|
3169
|
+
print("\nš Fixed commands:")
|
3170
|
+
for i, cmd in enumerate(fixed_commands, 1):
|
3171
|
+
print(f" {i}. {cmd}")
|
3172
|
+
|
3173
|
+
return fixed_commands
|
3174
|
+
else:
|
3175
|
+
print("ā ļø API response did not contain setupInstructions.commands field")
|
3176
|
+
except json.JSONDecodeError:
|
3177
|
+
print(f"ā Failed to parse API response as JSON")
|
3178
|
+
elif response:
|
3179
|
+
print(f"ā API request failed with status code: {response.status_code}")
|
3180
|
+
else:
|
3181
|
+
print(f"ā Failed to connect to {api_url}")
|
3100
3182
|
|
3183
|
+
print("ā All API endpoints failed")
|
3101
3184
|
return None
|
3102
3185
|
|
3103
3186
|
# Define a function to create and return a properly configured ssh container function
|
@@ -3388,9 +3471,248 @@ def show_usage_examples():
|
|
3388
3471
|
print("ā --volume-name my-persistent-volume ā")
|
3389
3472
|
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
3390
3473
|
|
3474
|
+
print("With GitIngest API (recommended)")
|
3475
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
3476
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ ā")
|
3477
|
+
print("ā --use-gitingest ā")
|
3478
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
3479
|
+
|
3480
|
+
print("With Original API")
|
3481
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā")
|
3482
|
+
print("ā gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ ā")
|
3483
|
+
print("ā --use-api ā")
|
3484
|
+
print("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n")
|
3485
|
+
|
3391
3486
|
print("Available GPU Options:")
|
3392
3487
|
print(" T4, L4, A10G, A100-40GB, A100-80GB, L40S, H100, H200, B200")
|
3393
3488
|
|
3489
|
+
def make_api_request_with_retry(url, payload, max_retries=2, timeout=180):
|
3490
|
+
"""Make an API request with retry mechanism."""
|
3491
|
+
import requests
|
3492
|
+
import time
|
3493
|
+
|
3494
|
+
for attempt in range(max_retries + 1):
|
3495
|
+
try:
|
3496
|
+
if attempt > 0:
|
3497
|
+
print(f"š Retry attempt {attempt}/{max_retries}...")
|
3498
|
+
|
3499
|
+
print(f"š Making POST request to: {url}")
|
3500
|
+
print(f"ā³ Waiting up to {timeout//60} minutes for response...")
|
3501
|
+
|
3502
|
+
# Set allow_redirects=True to follow redirects automatically
|
3503
|
+
response = requests.post(
|
3504
|
+
url,
|
3505
|
+
json=payload,
|
3506
|
+
timeout=timeout,
|
3507
|
+
allow_redirects=True,
|
3508
|
+
headers={
|
3509
|
+
'Content-Type': 'application/json',
|
3510
|
+
'User-Agent': 'GitArsenal-CLI/1.0'
|
3511
|
+
}
|
3512
|
+
)
|
3513
|
+
|
3514
|
+
# Print redirect info if any
|
3515
|
+
if response.history:
|
3516
|
+
print(f"ā
Request was redirected {len(response.history)} times")
|
3517
|
+
for resp in response.history:
|
3518
|
+
print(f" - Redirect: {resp.status_code} from {resp.url}")
|
3519
|
+
print(f"ā
Final URL: {response.url}")
|
3520
|
+
|
3521
|
+
return response
|
3522
|
+
except requests.exceptions.RequestException as e:
|
3523
|
+
if attempt < max_retries:
|
3524
|
+
retry_delay = 2 ** attempt # Exponential backoff
|
3525
|
+
print(f"ā ļø Request failed: {str(e)}")
|
3526
|
+
print(f"ā³ Waiting {retry_delay} seconds before retrying...")
|
3527
|
+
time.sleep(retry_delay)
|
3528
|
+
else:
|
3529
|
+
print(f"ā All retry attempts failed: {str(e)}")
|
3530
|
+
return None
|
3531
|
+
|
3532
|
+
return None
|
3533
|
+
|
3534
|
+
def get_setup_commands_from_gitingest(repo_url):
|
3535
|
+
"""
|
3536
|
+
Get repository setup commands using the gitingest approach.
|
3537
|
+
|
3538
|
+
This function is inspired by gitingest_setup_client.py and provides a more
|
3539
|
+
robust way to get setup commands for a repository.
|
3540
|
+
|
3541
|
+
Args:
|
3542
|
+
repo_url: URL of the repository to set up
|
3543
|
+
|
3544
|
+
Returns:
|
3545
|
+
List of setup commands or None if failed
|
3546
|
+
"""
|
3547
|
+
import requests
|
3548
|
+
import json
|
3549
|
+
import os
|
3550
|
+
import sys
|
3551
|
+
import tempfile
|
3552
|
+
import subprocess
|
3553
|
+
|
3554
|
+
print(f"š Getting setup commands for repository: {repo_url}")
|
3555
|
+
|
3556
|
+
# Define API endpoints to try in order
|
3557
|
+
api_endpoints = [
|
3558
|
+
"https://www.gitarsenal.dev/api/gitingest-setup-commands",
|
3559
|
+
"https://gitarsenal.dev/api/gitingest-setup-commands",
|
3560
|
+
"https://www.gitarsenal.dev/api/analyze-with-gitingest",
|
3561
|
+
"http://localhost:3000/api/gitingest-setup-commands"
|
3562
|
+
]
|
3563
|
+
|
3564
|
+
# Generate basic gitingest data
|
3565
|
+
def generate_basic_gitingest_data():
|
3566
|
+
# Extract repo name from URL
|
3567
|
+
repo_name = repo_url.split('/')[-1].replace('.git', '')
|
3568
|
+
|
3569
|
+
return {
|
3570
|
+
"system_info": {
|
3571
|
+
"platform": "Unknown",
|
3572
|
+
"python_version": "Unknown",
|
3573
|
+
"detected_language": "Unknown",
|
3574
|
+
"detected_technologies": [],
|
3575
|
+
"file_count": 0,
|
3576
|
+
"repo_stars": 0,
|
3577
|
+
"repo_forks": 0,
|
3578
|
+
"primary_package_manager": "Unknown",
|
3579
|
+
"complexity_level": "Unknown"
|
3580
|
+
},
|
3581
|
+
"repository_analysis": {
|
3582
|
+
"summary": f"Repository: {repo_name}",
|
3583
|
+
"tree": "",
|
3584
|
+
"content_preview": ""
|
3585
|
+
},
|
3586
|
+
"success": True
|
3587
|
+
}
|
3588
|
+
|
3589
|
+
# Try to generate gitingest data using CLI if available
|
3590
|
+
def generate_gitingest_data_from_cli():
|
3591
|
+
try:
|
3592
|
+
# Check if gitingest CLI is available
|
3593
|
+
subprocess.run(["gitingest", "--help"], check=True, capture_output=True, text=True)
|
3594
|
+
|
3595
|
+
# Create a temporary file for the output
|
3596
|
+
with tempfile.NamedTemporaryFile(suffix='.json', delete=False) as tmp:
|
3597
|
+
output_file = tmp.name
|
3598
|
+
|
3599
|
+
# Run gitingest command
|
3600
|
+
print(f"Running gitingest analysis on {repo_url}...")
|
3601
|
+
gitingest_cmd = ["gitingest", repo_url, "-o", output_file]
|
3602
|
+
result = subprocess.run(gitingest_cmd, capture_output=True, text=True)
|
3603
|
+
|
3604
|
+
if result.returncode != 0:
|
3605
|
+
print(f"GitIngest CLI failed: {result.stderr}")
|
3606
|
+
return None
|
3607
|
+
|
3608
|
+
# Read the output file
|
3609
|
+
try:
|
3610
|
+
with open(output_file, 'r', encoding='utf-8') as f:
|
3611
|
+
content = f.read()
|
3612
|
+
try:
|
3613
|
+
data = json.loads(content)
|
3614
|
+
return data
|
3615
|
+
except json.JSONDecodeError:
|
3616
|
+
# If not JSON, convert the text output to a basic structure
|
3617
|
+
return {
|
3618
|
+
"system_info": {
|
3619
|
+
"platform": "Unknown",
|
3620
|
+
"python_version": "Unknown",
|
3621
|
+
"detected_language": "Unknown",
|
3622
|
+
"detected_technologies": []
|
3623
|
+
},
|
3624
|
+
"repository_analysis": {
|
3625
|
+
"summary": content[:5000], # First 5000 chars as summary
|
3626
|
+
"tree": "",
|
3627
|
+
"content_preview": content[:10000] # First 10000 chars as preview
|
3628
|
+
},
|
3629
|
+
"success": True
|
3630
|
+
}
|
3631
|
+
except Exception as e:
|
3632
|
+
print(f"Error reading gitingest output: {e}")
|
3633
|
+
return None
|
3634
|
+
finally:
|
3635
|
+
# Clean up the temporary file
|
3636
|
+
if os.path.exists(output_file):
|
3637
|
+
os.unlink(output_file)
|
3638
|
+
|
3639
|
+
except (subprocess.SubprocessError, FileNotFoundError):
|
3640
|
+
print("GitIngest CLI not found")
|
3641
|
+
return None
|
3642
|
+
|
3643
|
+
# First try to get data from CLI
|
3644
|
+
gitingest_data = generate_gitingest_data_from_cli()
|
3645
|
+
|
3646
|
+
# If CLI failed, use basic data
|
3647
|
+
if not gitingest_data:
|
3648
|
+
print("Using basic gitingest data")
|
3649
|
+
gitingest_data = generate_basic_gitingest_data()
|
3650
|
+
|
3651
|
+
# Try each API endpoint
|
3652
|
+
for api_url in api_endpoints:
|
3653
|
+
try:
|
3654
|
+
print(f"Trying API endpoint: {api_url}")
|
3655
|
+
|
3656
|
+
payload = {
|
3657
|
+
"repoUrl": repo_url,
|
3658
|
+
"gitingestData": gitingest_data
|
3659
|
+
}
|
3660
|
+
|
3661
|
+
# Use the retry mechanism for more reliable requests
|
3662
|
+
response = make_api_request_with_retry(
|
3663
|
+
url=api_url,
|
3664
|
+
payload=payload,
|
3665
|
+
max_retries=2,
|
3666
|
+
timeout=180 # 3 minute timeout
|
3667
|
+
)
|
3668
|
+
|
3669
|
+
if not response:
|
3670
|
+
print(f"Failed to connect to {api_url}")
|
3671
|
+
continue
|
3672
|
+
|
3673
|
+
if response.status_code != 200:
|
3674
|
+
print(f"API request failed with status code: {response.status_code}")
|
3675
|
+
continue
|
3676
|
+
|
3677
|
+
try:
|
3678
|
+
result = response.json()
|
3679
|
+
|
3680
|
+
# Check if we have commands in the response
|
3681
|
+
commands = None
|
3682
|
+
|
3683
|
+
# Check for different response formats
|
3684
|
+
if "commands" in result:
|
3685
|
+
commands = result["commands"]
|
3686
|
+
elif "setupInstructions" in result and "commands" in result["setupInstructions"]:
|
3687
|
+
commands = result["setupInstructions"]["commands"]
|
3688
|
+
|
3689
|
+
if commands:
|
3690
|
+
print(f"ā
Successfully fetched {len(commands)} setup commands from API at {api_url}")
|
3691
|
+
|
3692
|
+
# Print the commands
|
3693
|
+
print("\nš Setup Commands:")
|
3694
|
+
for i, cmd in enumerate(commands, 1):
|
3695
|
+
print(f" {i}. {cmd}")
|
3696
|
+
|
3697
|
+
# Fix the commands
|
3698
|
+
fixed_commands = fix_setup_commands(commands)
|
3699
|
+
|
3700
|
+
# Print the fixed commands
|
3701
|
+
print("\nš Fixed commands:")
|
3702
|
+
for i, cmd in enumerate(fixed_commands, 1):
|
3703
|
+
print(f" {i}. {cmd}")
|
3704
|
+
|
3705
|
+
return fixed_commands
|
3706
|
+
else:
|
3707
|
+
print("No commands found in API response")
|
3708
|
+
except json.JSONDecodeError:
|
3709
|
+
print(f"Failed to parse API response as JSON")
|
3710
|
+
except Exception as e:
|
3711
|
+
print(f"Error with API endpoint {api_url}: {e}")
|
3712
|
+
|
3713
|
+
print("ā All API endpoints failed")
|
3714
|
+
return generate_fallback_commands(gitingest_data)
|
3715
|
+
|
3394
3716
|
if __name__ == "__main__":
|
3395
3717
|
# Parse command line arguments when script is run directly
|
3396
3718
|
import argparse
|
@@ -3409,6 +3731,7 @@ if __name__ == "__main__":
|
|
3409
3731
|
parser.add_argument('--timeout', type=int, default=60, help='Container timeout in minutes (default: 60)')
|
3410
3732
|
parser.add_argument('--ssh-password', type=str, help='SSH password (random if not provided)')
|
3411
3733
|
parser.add_argument('--use-api', action='store_true', help='Fetch setup commands from API')
|
3734
|
+
parser.add_argument('--use-gitingest', action='store_true', help='Use gitingest approach to fetch setup commands')
|
3412
3735
|
parser.add_argument('--show-examples', action='store_true', help='Show usage examples')
|
3413
3736
|
|
3414
3737
|
args = parser.parse_args()
|
@@ -3424,8 +3747,18 @@ if __name__ == "__main__":
|
|
3424
3747
|
|
3425
3748
|
# If --use-api flag is set and repo_url is provided, fetch setup commands from API
|
3426
3749
|
|
3750
|
+
# If --use-gitingest flag is set and repo_url is provided, use the gitingest approach
|
3751
|
+
if args.use_gitingest and args.repo_url:
|
3752
|
+
print("š Using gitingest approach to fetch setup commands")
|
3753
|
+
api_commands = get_setup_commands_from_gitingest(args.repo_url)
|
3754
|
+
if api_commands:
|
3755
|
+
setup_commands = api_commands
|
3756
|
+
print(f"š Using {len(setup_commands)} commands from gitingest API")
|
3757
|
+
else:
|
3758
|
+
print("ā ļø Failed to get commands from gitingest API, no fallback commands will be used")
|
3759
|
+
setup_commands = []
|
3427
3760
|
# If --use-api flag is set and repo_url is provided, fetch setup commands from API
|
3428
|
-
|
3761
|
+
elif args.use_api and args.repo_url:
|
3429
3762
|
print("š Using API to fetch setup commands")
|
3430
3763
|
api_commands = fetch_setup_commands_from_api(args.repo_url)
|
3431
3764
|
if api_commands:
|