File size: 6,893 Bytes
4b1daed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21629fd
 
e488fc6
14dca27
 
 
 
 
 
 
e488fc6
 
 
 
8431ee0
 
0198144
 
 
 
 
 
 
 
 
4fd00c2
 
194d369
 
 
 
 
 
 
 
 
 
4b1daed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

# Load environment variables manually
def load_env():
    env_path = Path(".env")
    if env_path.exists():
        with open(env_path, "r") as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                if "=" in line:
                    key, value = line.split("=", 1)
                    # Strip quotes if present
                    if (value.startswith('"') and value.endswith('"')) or \
                       (value.startswith("'") and value.endswith("'")):
                        value = value[1:-1]
                    os.environ[key] = value

load_env()

HF_TOKEN = os.getenv("HF_TOKEN")
HF_ORG = "AmaniQuery"

if not HF_TOKEN:
    print("Error: HF_TOKEN not found in .env file or environment variables.")
    sys.exit(1)

def run_command(command, cwd=None, env=None):
    try:
        updated_env = os.environ.copy()
        if env:
            updated_env.update(env)
            
        result = subprocess.run(
            command,
            cwd=cwd,
            env=updated_env,
            check=True,
            shell=True,
            capture_output=True,
            text=True
        )
        return result.stdout.strip()
    except subprocess.CalledProcessError as e:
        print(f"Error running command: {command}")
        print(f"Output: {e.stdout}")
        print(f"Error: {e.stderr}")
        raise

def deploy_service(service_type):
    # Configuration based on service type
    if service_type == "agent":
        repo_name = "amaniquery-agent"
        dockerfile_src = "deployments/huggingface/Dockerfile.hf"
        readme_src = "deployments/huggingface/README.md"
        context_path = "."
    elif service_type == "memory":
        repo_name = "amaniquery-memory"
        dockerfile_src = "deployments/huggingface/Dockerfile.rust.hf"
        readme_src = "deployments/huggingface/README.md" # We might need a specific one or just use default and edit
        context_path = "." # Rust service needs root context if using workspace
    else:
        print(f"Unknown service type: {service_type}")
        return

    print(f"Deploying {service_type} to https://huggingface.co/{HF_ORG}/{repo_name}...")

    # Create temp directory for cloning
    with tempfile.TemporaryDirectory() as temp_dir:
        repo_url = f"https://oauth2:{HF_TOKEN}@huggingface.co/spaces/{HF_ORG}/{repo_name}"
        
        print(f"Cloning {repo_name}...")
        try:
            run_command(f"git clone {repo_url} .", cwd=temp_dir)
        except Exception as e:
            print("Failed to clone. Make sure the Space exists first!")
            return

        # Configure git user
        run_command("git config user.email 'deploy-script@amaniquery.com'", cwd=temp_dir)
        run_command("git config user.name 'Deployment Script'", cwd=temp_dir)

        # Copy files respecting gitignore (using git ls-files to get list of tracked files)
        print("Copying files...")
        project_root = Path.cwd()
        
        # Get list of files tracked by git in current repo
        tracked_files = run_command("git ls-files", cwd=project_root).splitlines()
        
        for file_path in tracked_files:
            src = project_root / file_path
            dst = Path(temp_dir) / file_path
            
            # Skip deployments folder (handle separately to avoid overwriting custom setup)
            if file_path.startswith("deployments"):
                continue

            # Skip architectural diagrams and images
            if file_path.endswith(".png") or file_path.endswith(".jpg") or file_path.endswith(".jpeg"):
                continue
                
            dst.parent.mkdir(parents=True, exist_ok=True)
            if src.exists():
                shutil.copy2(src, dst)

        # Copy specific deployment artifacts
        print("Configuring deployment artifacts...")
        shutil.copy2(project_root / dockerfile_src, Path(temp_dir) / "Dockerfile")
        
        # Always overwrite README to ensure correct configuration
        shutil.copy2(project_root / readme_src, Path(temp_dir) / "README.md")

        # Explicitly copy start.sh (needed for runtime, might be untracked)
        start_sh_src = project_root / "deployments/huggingface/start.sh"
        start_sh_dst = Path(temp_dir) / "deployments/huggingface/start.sh"
        if start_sh_src.exists():
             start_sh_dst.parent.mkdir(parents=True, exist_ok=True)
             shutil.copy2(start_sh_src, start_sh_dst)

        for wfile in ["go.work", "go.work.sum"]:
            src = project_root / wfile
            if src.exists():
                shutil.copy2(src, Path(temp_dir) / wfile)
                # Force add because it might be in .gitignore
                run_command(f"git add -f {wfile}", cwd=temp_dir)

        # Explicitly copy rust-memory-service including Cargo.lock (which might be ignored or missed)
        rust_src = project_root / "rust-memory-service"
        rust_dst = Path(temp_dir) / "rust-memory-service"
        if rust_src.exists():
            # Remove destination if exists (from git ls-files copy) to ensure clean full copy
            if rust_dst.exists():
                shutil.rmtree(rust_dst)
            shutil.copytree(rust_src, rust_dst, ignore=shutil.ignore_patterns("target", ".git"))
            # Force add to ensure ignored files (like Cargo.lock if ignored) are included
            run_command("git add -f rust-memory-service", cwd=temp_dir)

        # Explicitly copy generated protobuf files (not tracked in git)
        proto_gen_src = project_root / "pkg/proto/gen"
        proto_gen_dst = Path(temp_dir) / "pkg/proto/gen"
        if proto_gen_src.exists():
            if proto_gen_dst.exists():
                shutil.rmtree(proto_gen_dst)
            proto_gen_dst.parent.mkdir(parents=True, exist_ok=True)
            shutil.copytree(proto_gen_src, proto_gen_dst)
            run_command("git add -f pkg/proto/gen", cwd=temp_dir)
        
        # Commit and push
        print("Pushing changes...")
        run_command("git add .", cwd=temp_dir)
        status = run_command("git status --porcelain", cwd=temp_dir)
        
        if status:
            run_command('git commit -m "Automated deployment update"', cwd=temp_dir)
            run_command("git push", cwd=temp_dir)
            print(f"Successfully deployed {service_type}!")
        else:
            print("No changes to deploy.")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python deploy_hf.py [agent|memory|all]")
        sys.exit(1)
        
    target = sys.argv[1]
    
    if target == "all":
        deploy_service("agent")
        deploy_service("memory")
    else:
        deploy_service(target)