clapp-pm 1.0.16__tar.gz → 1.0.18__tar.gz
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.
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/PKG-INFO +1 -1
- clapp_pm-1.0.18/cache_manager.py +376 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_pm.egg-info/SOURCES.txt +8 -2
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_pm.egg-info/top_level.txt +4 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/deploy.py +26 -11
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/main.py +183 -0
- clapp_pm-1.0.18/package_signing.py +370 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/requirements.txt +7 -1
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/setup.py +4 -0
- clapp_pm-1.0.18/smart_search.py +451 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/version.json +1 -1
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/version.py +1 -1
- clapp_pm-1.0.18/version_manager.py +351 -0
- clapp_pm-1.0.16/pypi_token.txt +0 -1
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/CHANGELOG.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/GITHUB_SETUP.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/LICENSE +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/MANIFEST.in +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/PYPI_UPLOAD.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/README.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/advanced_test.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/build_index.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/check_env.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/clapp_core.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/clean_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/cli_commands.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/dependency_resolver.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/doctor_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/info_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/install_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/installer.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/list_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/manifest_schema.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/manifest_validator.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/package_registry.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/package_runner.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/post_install_hint.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/publish_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/remote_registry.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/setup.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/system_test.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/uninstall_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/validate_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/version.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/version_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/backup_current/where_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/build_index.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/check_env.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/README.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/index.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/hello-python/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/hello-python/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/test-app/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/test-app/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/test-app2/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages/test-app2/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp-packages-repo/packages.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_app_structure.md +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_core.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_pm.egg-info/dependency_links.txt +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_pm.egg-info/entry_points.txt +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clapp_pm.egg-info/requires.txt +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/clean_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/cli_commands.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/dependency_resolver.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/doctor_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/index.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/info_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/install_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/installer.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/list_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/manifest_schema.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/manifest_validator.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/package_registry.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/package_runner.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/hello-python/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/hello-python/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/test-app/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/test-app/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/test-app2/main.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/packages/test-app2/manifest.json +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/post_install_hint.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/publish_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/pyproject.toml +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/remote_registry.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/setup.cfg +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/system_test.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/uninstall_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/validate_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/version_command.py +0 -0
- {clapp_pm-1.0.16 → clapp_pm-1.0.18}/where_command.py +0 -0
@@ -0,0 +1,376 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
cache_manager.py - Performans Optimizasyonu ve Önbellekleme Sistemi
|
4
|
+
|
5
|
+
Bu modül clapp'in performansını artırmak için:
|
6
|
+
- Paket meta verilerini önbellekleme
|
7
|
+
- Registry verilerini önbellekleme
|
8
|
+
- Dosya checksum'larını önbellekleme
|
9
|
+
- Akıllı cache yönetimi
|
10
|
+
- Paralel indirme desteği
|
11
|
+
"""
|
12
|
+
|
13
|
+
import os
|
14
|
+
import json
|
15
|
+
import hashlib
|
16
|
+
import pickle
|
17
|
+
import threading
|
18
|
+
import time
|
19
|
+
from pathlib import Path
|
20
|
+
from typing import Dict, Any, Optional, List, Tuple
|
21
|
+
from datetime import datetime, timedelta
|
22
|
+
import concurrent.futures
|
23
|
+
import requests
|
24
|
+
from functools import wraps
|
25
|
+
|
26
|
+
class CacheManager:
|
27
|
+
"""Akıllı önbellekleme yöneticisi"""
|
28
|
+
|
29
|
+
def __init__(self, cache_dir: Optional[str] = None):
|
30
|
+
"""
|
31
|
+
CacheManager başlatıcısı
|
32
|
+
|
33
|
+
Args:
|
34
|
+
cache_dir: Cache dizini (varsayılan: ~/.clapp/cache)
|
35
|
+
"""
|
36
|
+
if cache_dir is None:
|
37
|
+
cache_dir = os.path.join(os.path.expanduser("~"), ".clapp", "cache")
|
38
|
+
|
39
|
+
self.cache_dir = Path(cache_dir)
|
40
|
+
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
41
|
+
|
42
|
+
# Cache türleri
|
43
|
+
self.metadata_cache = self.cache_dir / "metadata"
|
44
|
+
self.registry_cache = self.cache_dir / "registry"
|
45
|
+
self.checksum_cache = self.cache_dir / "checksums"
|
46
|
+
self.download_cache = self.cache_dir / "downloads"
|
47
|
+
|
48
|
+
# Cache dizinlerini oluştur
|
49
|
+
for cache_path in [self.metadata_cache, self.registry_cache,
|
50
|
+
self.checksum_cache, self.download_cache]:
|
51
|
+
cache_path.mkdir(exist_ok=True)
|
52
|
+
|
53
|
+
# Cache istatistikleri
|
54
|
+
self.stats = {
|
55
|
+
"hits": 0,
|
56
|
+
"misses": 0,
|
57
|
+
"evictions": 0,
|
58
|
+
"size": 0
|
59
|
+
}
|
60
|
+
|
61
|
+
# Thread-safe cache
|
62
|
+
self._lock = threading.Lock()
|
63
|
+
|
64
|
+
def _get_cache_key(self, key: str, cache_type: str = "metadata") -> Path:
|
65
|
+
"""Cache anahtarı için dosya yolu oluşturur"""
|
66
|
+
if cache_type == "metadata":
|
67
|
+
return self.metadata_cache / f"{key}.json"
|
68
|
+
elif cache_type == "registry":
|
69
|
+
return self.registry_cache / f"{key}.json"
|
70
|
+
elif cache_type == "checksum":
|
71
|
+
return self.checksum_cache / f"{key}.txt"
|
72
|
+
elif cache_type == "download":
|
73
|
+
return self.download_cache / f"{key}.zip"
|
74
|
+
else:
|
75
|
+
raise ValueError(f"Geçersiz cache türü: {cache_type}")
|
76
|
+
|
77
|
+
def get(self, key: str, cache_type: str = "metadata", max_age: int = 3600) -> Optional[Any]:
|
78
|
+
"""
|
79
|
+
Cache'den veri alır
|
80
|
+
|
81
|
+
Args:
|
82
|
+
key: Cache anahtarı
|
83
|
+
cache_type: Cache türü
|
84
|
+
max_age: Maksimum yaş (saniye)
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
Cache'lenmiş veri veya None
|
88
|
+
"""
|
89
|
+
cache_file = self._get_cache_key(key, cache_type)
|
90
|
+
|
91
|
+
if not cache_file.exists():
|
92
|
+
self.stats["misses"] += 1
|
93
|
+
return None
|
94
|
+
|
95
|
+
# Dosya yaşını kontrol et
|
96
|
+
file_age = time.time() - cache_file.stat().st_mtime
|
97
|
+
if file_age > max_age:
|
98
|
+
cache_file.unlink()
|
99
|
+
self.stats["misses"] += 1
|
100
|
+
return None
|
101
|
+
|
102
|
+
try:
|
103
|
+
with self._lock:
|
104
|
+
if cache_type in ["metadata", "registry"]:
|
105
|
+
with open(cache_file, 'r', encoding='utf-8') as f:
|
106
|
+
data = json.load(f)
|
107
|
+
elif cache_type == "checksum":
|
108
|
+
with open(cache_file, 'r', encoding='utf-8') as f:
|
109
|
+
data = f.read().strip()
|
110
|
+
else:
|
111
|
+
# Binary dosyalar için pickle kullan
|
112
|
+
with open(cache_file, 'rb') as f:
|
113
|
+
data = pickle.load(f)
|
114
|
+
|
115
|
+
self.stats["hits"] += 1
|
116
|
+
return data
|
117
|
+
|
118
|
+
except Exception as e:
|
119
|
+
print(f"Cache okuma hatası: {e}")
|
120
|
+
cache_file.unlink()
|
121
|
+
self.stats["misses"] += 1
|
122
|
+
return None
|
123
|
+
|
124
|
+
def set(self, key: str, data: Any, cache_type: str = "metadata") -> bool:
|
125
|
+
"""
|
126
|
+
Cache'e veri kaydeder
|
127
|
+
|
128
|
+
Args:
|
129
|
+
key: Cache anahtarı
|
130
|
+
data: Kaydedilecek veri
|
131
|
+
cache_type: Cache türü
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
Başarılıysa True
|
135
|
+
"""
|
136
|
+
cache_file = self._get_cache_key(key, cache_type)
|
137
|
+
|
138
|
+
try:
|
139
|
+
with self._lock:
|
140
|
+
if cache_type in ["metadata", "registry"]:
|
141
|
+
with open(cache_file, 'w', encoding='utf-8') as f:
|
142
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
143
|
+
elif cache_type == "checksum":
|
144
|
+
with open(cache_file, 'w', encoding='utf-8') as f:
|
145
|
+
f.write(str(data))
|
146
|
+
else:
|
147
|
+
# Binary dosyalar için pickle kullan
|
148
|
+
with open(cache_file, 'wb') as f:
|
149
|
+
pickle.dump(data, f)
|
150
|
+
|
151
|
+
return True
|
152
|
+
|
153
|
+
except Exception as e:
|
154
|
+
print(f"Cache yazma hatası: {e}")
|
155
|
+
return False
|
156
|
+
|
157
|
+
def delete(self, key: str, cache_type: str = "metadata") -> bool:
|
158
|
+
"""Cache'den veri siler"""
|
159
|
+
cache_file = self._get_cache_key(key, cache_type)
|
160
|
+
|
161
|
+
try:
|
162
|
+
if cache_file.exists():
|
163
|
+
cache_file.unlink()
|
164
|
+
return True
|
165
|
+
return False
|
166
|
+
except Exception:
|
167
|
+
return False
|
168
|
+
|
169
|
+
def clear(self, cache_type: Optional[str] = None) -> int:
|
170
|
+
"""
|
171
|
+
Cache'i temizler
|
172
|
+
|
173
|
+
Args:
|
174
|
+
cache_type: Temizlenecek cache türü (None ise tümü)
|
175
|
+
|
176
|
+
Returns:
|
177
|
+
Silinen dosya sayısı
|
178
|
+
"""
|
179
|
+
deleted_count = 0
|
180
|
+
|
181
|
+
if cache_type:
|
182
|
+
cache_path = self._get_cache_key("", cache_type).parent
|
183
|
+
if cache_path.exists():
|
184
|
+
for file in cache_path.iterdir():
|
185
|
+
if file.is_file():
|
186
|
+
file.unlink()
|
187
|
+
deleted_count += 1
|
188
|
+
else:
|
189
|
+
# Tüm cache'leri temizle
|
190
|
+
for cache_path in [self.metadata_cache, self.registry_cache,
|
191
|
+
self.checksum_cache, self.download_cache]:
|
192
|
+
if cache_path.exists():
|
193
|
+
for file in cache_path.iterdir():
|
194
|
+
if file.is_file():
|
195
|
+
file.unlink()
|
196
|
+
deleted_count += 1
|
197
|
+
|
198
|
+
return deleted_count
|
199
|
+
|
200
|
+
def get_stats(self) -> Dict[str, Any]:
|
201
|
+
"""Cache istatistiklerini döndürür"""
|
202
|
+
total_size = 0
|
203
|
+
|
204
|
+
# Cache boyutunu hesapla
|
205
|
+
for cache_path in [self.metadata_cache, self.registry_cache,
|
206
|
+
self.checksum_cache, self.download_cache]:
|
207
|
+
if cache_path.exists():
|
208
|
+
for file in cache_path.iterdir():
|
209
|
+
if file.is_file():
|
210
|
+
total_size += file.stat().st_size
|
211
|
+
|
212
|
+
return {
|
213
|
+
**self.stats,
|
214
|
+
"size_bytes": total_size,
|
215
|
+
"size_mb": round(total_size / (1024 * 1024), 2),
|
216
|
+
"hit_rate": round(self.stats["hits"] / max(1, self.stats["hits"] + self.stats["misses"]) * 100, 2)
|
217
|
+
}
|
218
|
+
|
219
|
+
def calculate_checksum(self, file_path: str) -> str:
|
220
|
+
"""Dosyanın SHA-256 checksum'unu hesaplar ve cache'ler"""
|
221
|
+
cache_key = hashlib.md5(file_path.encode()).hexdigest()
|
222
|
+
cached_checksum = self.get(cache_key, "checksum", max_age=86400) # 24 saat
|
223
|
+
|
224
|
+
if cached_checksum:
|
225
|
+
return cached_checksum
|
226
|
+
|
227
|
+
# Checksum hesapla
|
228
|
+
sha256_hash = hashlib.sha256()
|
229
|
+
with open(file_path, "rb") as f:
|
230
|
+
for chunk in iter(lambda: f.read(4096), b""):
|
231
|
+
sha256_hash.update(chunk)
|
232
|
+
|
233
|
+
checksum = sha256_hash.hexdigest()
|
234
|
+
self.set(cache_key, checksum, "checksum")
|
235
|
+
|
236
|
+
return checksum
|
237
|
+
|
238
|
+
def cache_package_metadata(self, package_path: str, metadata: Dict[str, Any]) -> bool:
|
239
|
+
"""Paket meta verilerini cache'ler"""
|
240
|
+
cache_key = hashlib.md5(package_path.encode()).hexdigest()
|
241
|
+
return self.set(cache_key, metadata, "metadata")
|
242
|
+
|
243
|
+
def get_cached_package_metadata(self, package_path: str) -> Optional[Dict[str, Any]]:
|
244
|
+
"""Cache'lenmiş paket meta verilerini alır"""
|
245
|
+
cache_key = hashlib.md5(package_path.encode()).hexdigest()
|
246
|
+
return self.get(cache_key, "metadata", max_age=3600) # 1 saat
|
247
|
+
|
248
|
+
def cache_registry_data(self, registry_url: str, data: List[Dict[str, Any]]) -> bool:
|
249
|
+
"""Registry verilerini cache'ler"""
|
250
|
+
cache_key = hashlib.md5(registry_url.encode()).hexdigest()
|
251
|
+
return self.set(cache_key, data, "registry")
|
252
|
+
|
253
|
+
def get_cached_registry_data(self, registry_url: str) -> Optional[List[Dict[str, Any]]]:
|
254
|
+
"""Cache'lenmiş registry verilerini alır"""
|
255
|
+
cache_key = hashlib.md5(registry_url.encode()).hexdigest()
|
256
|
+
return self.get(cache_key, "registry", max_age=1800) # 30 dakika
|
257
|
+
|
258
|
+
class ParallelDownloader:
|
259
|
+
"""Paralel indirme yöneticisi"""
|
260
|
+
|
261
|
+
def __init__(self, max_workers: int = 4):
|
262
|
+
"""
|
263
|
+
ParallelDownloader başlatıcısı
|
264
|
+
|
265
|
+
Args:
|
266
|
+
max_workers: Maksimum paralel işçi sayısı
|
267
|
+
"""
|
268
|
+
self.max_workers = max_workers
|
269
|
+
self.session = requests.Session()
|
270
|
+
self.session.headers.update({
|
271
|
+
'User-Agent': 'clapp-package-manager/1.0'
|
272
|
+
})
|
273
|
+
|
274
|
+
def download_file(self, url: str, destination: str) -> Tuple[bool, str]:
|
275
|
+
"""Tek dosya indirir"""
|
276
|
+
try:
|
277
|
+
response = self.session.get(url, stream=True, timeout=30)
|
278
|
+
response.raise_for_status()
|
279
|
+
|
280
|
+
with open(destination, 'wb') as f:
|
281
|
+
for chunk in response.iter_content(chunk_size=8192):
|
282
|
+
f.write(chunk)
|
283
|
+
|
284
|
+
return True, f"Dosya indirildi: {destination}"
|
285
|
+
|
286
|
+
except Exception as e:
|
287
|
+
return False, f"İndirme hatası: {str(e)}"
|
288
|
+
|
289
|
+
def download_files_parallel(self, download_tasks: List[Tuple[str, str]]) -> List[Tuple[bool, str]]:
|
290
|
+
"""
|
291
|
+
Birden fazla dosyayı paralel indirir
|
292
|
+
|
293
|
+
Args:
|
294
|
+
download_tasks: [(url, destination), ...] listesi
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
[(success, message), ...] listesi
|
298
|
+
"""
|
299
|
+
results = []
|
300
|
+
|
301
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
302
|
+
# İndirme görevlerini başlat
|
303
|
+
future_to_task = {
|
304
|
+
executor.submit(self.download_file, url, dest): (url, dest)
|
305
|
+
for url, dest in download_tasks
|
306
|
+
}
|
307
|
+
|
308
|
+
# Sonuçları topla
|
309
|
+
for future in concurrent.futures.as_completed(future_to_task):
|
310
|
+
task = future_to_task[future]
|
311
|
+
try:
|
312
|
+
result = future.result()
|
313
|
+
results.append(result)
|
314
|
+
except Exception as e:
|
315
|
+
results.append((False, f"İndirme hatası: {str(e)}"))
|
316
|
+
|
317
|
+
return results
|
318
|
+
|
319
|
+
# Cache decorator
|
320
|
+
def cached(max_age: int = 3600, cache_type: str = "metadata"):
|
321
|
+
"""Cache decorator'ı"""
|
322
|
+
def decorator(func):
|
323
|
+
@wraps(func)
|
324
|
+
def wrapper(*args, **kwargs):
|
325
|
+
# Cache anahtarı oluştur
|
326
|
+
cache_key = f"{func.__name__}_{hash(str(args) + str(sorted(kwargs.items())))}"
|
327
|
+
|
328
|
+
# Cache manager oluştur
|
329
|
+
cache_manager = CacheManager()
|
330
|
+
|
331
|
+
# Cache'den kontrol et
|
332
|
+
cached_result = cache_manager.get(cache_key, cache_type, max_age)
|
333
|
+
if cached_result is not None:
|
334
|
+
return cached_result
|
335
|
+
|
336
|
+
# Fonksiyonu çalıştır
|
337
|
+
result = func(*args, **kwargs)
|
338
|
+
|
339
|
+
# Sonucu cache'le
|
340
|
+
cache_manager.set(cache_key, result, cache_type)
|
341
|
+
|
342
|
+
return result
|
343
|
+
return wrapper
|
344
|
+
return decorator
|
345
|
+
|
346
|
+
# Yardımcı fonksiyonlar
|
347
|
+
def create_cache_manager() -> CacheManager:
|
348
|
+
"""Varsayılan ayarlarla CacheManager oluşturur"""
|
349
|
+
return CacheManager()
|
350
|
+
|
351
|
+
def create_parallel_downloader(max_workers: int = 4) -> ParallelDownloader:
|
352
|
+
"""ParallelDownloader oluşturur"""
|
353
|
+
return ParallelDownloader(max_workers)
|
354
|
+
|
355
|
+
def get_cache_stats() -> Dict[str, Any]:
|
356
|
+
"""Cache istatistiklerini alır"""
|
357
|
+
cache_manager = create_cache_manager()
|
358
|
+
return cache_manager.get_stats()
|
359
|
+
|
360
|
+
def clear_all_caches() -> int:
|
361
|
+
"""Tüm cache'leri temizler"""
|
362
|
+
cache_manager = create_cache_manager()
|
363
|
+
return cache_manager.clear()
|
364
|
+
|
365
|
+
def download_packages_parallel(package_urls: List[str], destination_dir: str) -> List[Tuple[bool, str]]:
|
366
|
+
"""Paketleri paralel indirir"""
|
367
|
+
downloader = create_parallel_downloader()
|
368
|
+
|
369
|
+
# İndirme görevlerini hazırla
|
370
|
+
download_tasks = []
|
371
|
+
for url in package_urls:
|
372
|
+
filename = os.path.basename(url)
|
373
|
+
destination = os.path.join(destination_dir, filename)
|
374
|
+
download_tasks.append((url, destination))
|
375
|
+
|
376
|
+
return downloader.download_files_parallel(download_tasks)
|
@@ -5,6 +5,7 @@ PYPI_UPLOAD.md
|
|
5
5
|
README.md
|
6
6
|
advanced_test.py
|
7
7
|
build_index.py
|
8
|
+
cache_manager.py
|
8
9
|
check_env.py
|
9
10
|
clapp_app_structure.md
|
10
11
|
clapp_core.py
|
@@ -23,19 +24,21 @@ manifest_schema.py
|
|
23
24
|
manifest_validator.py
|
24
25
|
package_registry.py
|
25
26
|
package_runner.py
|
27
|
+
package_signing.py
|
26
28
|
post_install_hint.py
|
27
29
|
publish_command.py
|
28
|
-
pypi_token.txt
|
29
30
|
pyproject.toml
|
30
31
|
remote_registry.py
|
31
32
|
requirements.txt
|
32
33
|
setup.py
|
34
|
+
smart_search.py
|
33
35
|
system_test.py
|
34
36
|
uninstall_command.py
|
35
37
|
validate_command.py
|
36
38
|
version.json
|
37
39
|
version.py
|
38
40
|
version_command.py
|
41
|
+
version_manager.py
|
39
42
|
where_command.py
|
40
43
|
./CHANGELOG.md
|
41
44
|
./GITHUB_SETUP.md
|
@@ -43,6 +46,7 @@ where_command.py
|
|
43
46
|
./README.md
|
44
47
|
./advanced_test.py
|
45
48
|
./build_index.py
|
49
|
+
./cache_manager.py
|
46
50
|
./check_env.py
|
47
51
|
./clapp_app_structure.md
|
48
52
|
./clapp_core.py
|
@@ -61,18 +65,20 @@ where_command.py
|
|
61
65
|
./manifest_validator.py
|
62
66
|
./package_registry.py
|
63
67
|
./package_runner.py
|
68
|
+
./package_signing.py
|
64
69
|
./post_install_hint.py
|
65
70
|
./publish_command.py
|
66
|
-
./pypi_token.txt
|
67
71
|
./remote_registry.py
|
68
72
|
./requirements.txt
|
69
73
|
./setup.py
|
74
|
+
./smart_search.py
|
70
75
|
./system_test.py
|
71
76
|
./uninstall_command.py
|
72
77
|
./validate_command.py
|
73
78
|
./version.json
|
74
79
|
./version.py
|
75
80
|
./version_command.py
|
81
|
+
./version_manager.py
|
76
82
|
./where_command.py
|
77
83
|
./backup_current/build_index.py
|
78
84
|
./backup_current/check_env.py
|
@@ -1,4 +1,5 @@
|
|
1
1
|
backup_current
|
2
|
+
cache_manager
|
2
3
|
check_env
|
3
4
|
clapp-packages-repo
|
4
5
|
clapp_core
|
@@ -16,12 +17,15 @@ manifest_schema
|
|
16
17
|
manifest_validator
|
17
18
|
package_registry
|
18
19
|
package_runner
|
20
|
+
package_signing
|
19
21
|
packages
|
20
22
|
post_install_hint
|
21
23
|
publish_command
|
22
24
|
remote_registry
|
25
|
+
smart_search
|
23
26
|
uninstall_command
|
24
27
|
validate_command
|
25
28
|
version
|
26
29
|
version_command
|
30
|
+
version_manager
|
27
31
|
where_command
|
@@ -17,18 +17,33 @@ import subprocess
|
|
17
17
|
import argparse
|
18
18
|
from pathlib import Path
|
19
19
|
|
20
|
-
def
|
21
|
-
"""PyPI token'ını
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
def get_pypi_token():
|
21
|
+
"""PyPI token'ını kullanıcıdan alır"""
|
22
|
+
print("🔐 PyPI Token Gerekli")
|
23
|
+
print("Token'ı https://pypi.org/manage/account/token/ adresinden alabilirsiniz")
|
24
|
+
print("Token formatı: pypi-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
25
|
+
print()
|
26
|
+
|
27
|
+
while True:
|
28
|
+
token = input("PyPI Token'ınızı girin: ").strip()
|
29
|
+
|
30
|
+
if not token:
|
31
|
+
print("❌ Token boş olamaz!")
|
32
|
+
continue
|
33
|
+
|
34
|
+
if not token.startswith("pypi-"):
|
35
|
+
print("❌ Token 'pypi-' ile başlamalı!")
|
36
|
+
continue
|
37
|
+
|
38
|
+
if len(token) < 50:
|
39
|
+
print("❌ Token çok kısa görünüyor!")
|
40
|
+
continue
|
41
|
+
|
42
|
+
print("✅ Token formatı doğru")
|
43
|
+
return token
|
29
44
|
|
30
|
-
# PyPI Token'ı
|
31
|
-
PYPI_TOKEN =
|
45
|
+
# PyPI Token'ı kullanıcıdan al
|
46
|
+
PYPI_TOKEN = get_pypi_token()
|
32
47
|
|
33
48
|
def run_command(command, description, check=True):
|
34
49
|
"""Komut çalıştırır ve sonucu döndürür"""
|