clapp-pm 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.
main.py ADDED
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ main.py - clapp Ana CLI Giriş Noktası
4
+
5
+ Bu dosya clapp'in ana komut satırı arayüzüdür.
6
+ Tüm komutları yönlendirir ve kullanıcı deneyimini yönetir.
7
+ """
8
+
9
+ import argparse
10
+ import sys
11
+ import os
12
+ from pathlib import Path
13
+
14
+ # Mevcut modülleri import et
15
+ from clapp_core import list_apps, run_app
16
+ from cli_commands import (
17
+ install_from_remote, upgrade_package, publish_package,
18
+ search_remote_packages, show_package_info, list_all_packages,
19
+ check_system_health, handle_publish_command, handle_install_command,
20
+ handle_uninstall_command, handle_list_command, publish_to_repository
21
+ )
22
+ from installer import install_package, uninstall_package, install_from_directory
23
+ from remote_registry import list_remote_packages
24
+
25
+ # Yeni komut modüllerini import et
26
+ from post_install_hint import check_first_run, show_post_install_hint
27
+ from check_env import run_environment_check
28
+ from info_command import show_app_info
29
+ from validate_command import validate_app_folder
30
+ from doctor_command import run_doctor
31
+ from clean_command import run_clean
32
+ from where_command import locate_app_path, list_all_app_locations
33
+ from version_command import print_version, print_detailed_version
34
+
35
+ # Yeni publish.cursorrules komutları
36
+ from publish_command import publish_app
37
+ from install_command import install_app
38
+ from uninstall_command import uninstall_app
39
+ from list_command import list_apps as list_apps_new
40
+
41
+ def main():
42
+ """Ana CLI fonksiyonu"""
43
+
44
+ # İlk çalıştırma kontrolü
45
+ first_run = check_first_run()
46
+ if first_run:
47
+ print() # Boş satır ekle
48
+
49
+ parser = argparse.ArgumentParser(
50
+ prog='clapp',
51
+ description='🚀 clapp - Hafif Çoklu Dil Uygulama Yöneticisi',
52
+ formatter_class=argparse.RawDescriptionHelpFormatter,
53
+ epilog="""
54
+ 📚 Temel Komutlar:
55
+ clapp list # Yüklü uygulamaları listele
56
+ clapp run hello-python # hello-python uygulamasını çalıştır
57
+ clapp info hello-python # Uygulama bilgilerini göster
58
+
59
+ 🔧 Yönetim Komutları:
60
+ clapp install app.zip # ZIP dosyasından uygulama yükle
61
+ clapp uninstall hello-python # Uygulamayı kaldır
62
+ clapp upgrade hello-python # Uygulamayı güncelle
63
+ clapp validate ./my-app # Uygulama klasörünü doğrula
64
+ clapp publish ./my-app # Uygulama yayınla
65
+
66
+ 🛠️ Sistem Komutları:
67
+ clapp check-env # Ortam kontrolü
68
+ clapp doctor # Kapsamlı sistem tanılaması
69
+ clapp clean # Geçici dosyaları temizle
70
+ clapp where hello-python # Uygulama konumunu göster
71
+ clapp version # Sürüm bilgilerini göster
72
+
73
+ 🌐 Uzak Komutlar:
74
+ clapp search calculator # Uzak depoda ara
75
+ clapp remote list # Uzak depo listesi
76
+ clapp health # Sistem sağlık kontrolü
77
+
78
+ 📖 Daha fazla bilgi için: https://github.com/mburakmmm/clapp
79
+ """
80
+ )
81
+
82
+ # Alt komutlar
83
+ subparsers = parser.add_subparsers(dest='command', help='Mevcut komutlar')
84
+
85
+ # run komutu
86
+ run_parser = subparsers.add_parser('run', help='Yüklü bir uygulamayı çalıştır')
87
+ run_parser.add_argument('app_name', help='Çalıştırılacak uygulamanın adı')
88
+
89
+ # list komutu
90
+ list_parser = subparsers.add_parser('list', help='Yüklü uygulamaları listele')
91
+ list_parser.add_argument('--all', action='store_true', help='Hem yerel hem uzak paketleri listele')
92
+ list_parser.add_argument('--format', choices=['table', 'simple', 'json', 'detailed'],
93
+ default='table', help='Çıktı formatı')
94
+ list_parser.add_argument('--language', help='Dil filtresi (python, lua, vb.)')
95
+ list_parser.add_argument('--search', help='Arama terimi (ad veya açıklamada)')
96
+
97
+ # install komutu
98
+ install_parser = subparsers.add_parser('install', help='Uygulama yükle')
99
+ install_parser.add_argument('source', help='Uygulama adı, zip dosyası veya URL')
100
+ install_parser.add_argument('--force', action='store_true', help='Mevcut uygulamanın üzerine yaz')
101
+ install_parser.add_argument('--local', action='store_true', help='Yerel dizinden yükle')
102
+
103
+ # uninstall komutu
104
+ uninstall_parser = subparsers.add_parser('uninstall', help='Uygulama kaldır')
105
+ uninstall_parser.add_argument('app_name', help='Kaldırılacak uygulamanın adı')
106
+ uninstall_parser.add_argument('--yes', action='store_true', help='Onay sorma')
107
+
108
+ # upgrade komutu
109
+ upgrade_parser = subparsers.add_parser('upgrade', help='Uygulamayı güncelle')
110
+ upgrade_parser.add_argument('app_name', help='Güncellenecek uygulamanın adı')
111
+
112
+ # search komutu
113
+ search_parser = subparsers.add_parser('search', help='Paket ara')
114
+ search_parser.add_argument('query', help='Arama terimi')
115
+
116
+ # info komutu (yeni)
117
+ info_parser = subparsers.add_parser('info', help='Uygulama bilgilerini detaylı göster')
118
+ info_parser.add_argument('app_name', help='Bilgisi gösterilecek uygulamanın adı')
119
+ info_parser.add_argument('--remote', action='store_true', help='Uzak paket bilgisini göster')
120
+
121
+ # validate komutu (yeni)
122
+ validate_parser = subparsers.add_parser('validate', help='Uygulama klasörünü doğrula')
123
+ validate_parser.add_argument('folder', help='Doğrulanacak klasör yolu')
124
+
125
+ # publish komutu
126
+ publish_parser = subparsers.add_parser('publish', help='Paket yayınla')
127
+ publish_parser.add_argument('app_path', help='Yayınlanacak uygulama dizini')
128
+ publish_parser.add_argument('--push', action='store_true', help='clapp-packages reposuna otomatik push et')
129
+
130
+ # remote komutu
131
+ remote_parser = subparsers.add_parser('remote', help='Uzak paket deposunu listele')
132
+ remote_parser.add_argument('--details', action='store_true', help='Detayları göster')
133
+
134
+ # health komutu
135
+ health_parser = subparsers.add_parser('health', help='Sistem sağlığını kontrol et')
136
+
137
+ # check-env komutu (yeni)
138
+ check_env_parser = subparsers.add_parser('check-env', help='Ortam kontrolü yap')
139
+
140
+ # doctor komutu (yeni)
141
+ doctor_parser = subparsers.add_parser('doctor', help='Kapsamlı sistem tanılaması')
142
+
143
+ # clean komutu (yeni)
144
+ clean_parser = subparsers.add_parser('clean', help='Geçici dosyaları temizle')
145
+ clean_parser.add_argument('--dry-run', action='store_true', help='Sadece göster, silme')
146
+
147
+ # where komutu (yeni)
148
+ where_parser = subparsers.add_parser('where', help='Uygulama konumunu göster')
149
+ where_parser.add_argument('app_name', nargs='?', help='Konumu gösterilecek uygulamanın adı')
150
+ where_parser.add_argument('--check-entry', action='store_true', help='Giriş dosyasını da kontrol et')
151
+ where_parser.add_argument('--open', action='store_true', help='Dosya yöneticisinde aç')
152
+
153
+
154
+
155
+ # version komutu (yeni)
156
+ version_parser = subparsers.add_parser('version', help='Sürüm bilgisini göster')
157
+ version_parser.add_argument('--short', action='store_true', help='Sadece sürüm numarası')
158
+ version_parser.add_argument('--json', action='store_true', help='JSON formatında')
159
+ version_parser.add_argument('--detailed', action='store_true', help='Detaylı bilgi')
160
+
161
+ # Argümanları parse et
162
+ args = parser.parse_args()
163
+
164
+ # Komut yoksa help göster
165
+ if not args.command:
166
+ parser.print_help()
167
+ return
168
+
169
+ try:
170
+ # Komutları işle
171
+ if args.command == 'run':
172
+ success = run_app(args.app_name)
173
+ sys.exit(0 if success else 1)
174
+
175
+ elif args.command == 'list':
176
+ if args.all:
177
+ list_all_packages()
178
+ else:
179
+ # Yeni gelişmiş list komutu
180
+ try:
181
+ output = list_apps_new(args.format, args.language, args.search)
182
+ print(output)
183
+ except Exception as e:
184
+ print(f"❌ Liste hatası: {e}")
185
+ sys.exit(1)
186
+
187
+ elif args.command == 'install':
188
+ if args.local:
189
+ # Yerel dizinden yükle
190
+ success, message = install_from_directory(args.source, args.force)
191
+ elif args.source.endswith('.zip') or '/' in args.source:
192
+ # Zip dosyası veya URL
193
+ success, message = install_package(args.source, args.force)
194
+ else:
195
+ # Yeni install komutu (GitHub'dan index.json ile)
196
+ success, message = install_app(args.source)
197
+
198
+ if not success:
199
+ print(f"❌ {message}")
200
+ sys.exit(1)
201
+
202
+ elif args.command == 'uninstall':
203
+ # Yeni uninstall komutu
204
+ success, message = uninstall_app(args.app_name, args.yes)
205
+ print(message)
206
+ sys.exit(0 if success else 1)
207
+
208
+ elif args.command == 'upgrade':
209
+ success, message = upgrade_package(args.app_name)
210
+ if not success:
211
+ print(f"❌ {message}")
212
+ sys.exit(1)
213
+
214
+ elif args.command == 'search':
215
+ success, message = search_remote_packages(args.query)
216
+ if not success:
217
+ print(f"❌ {message}")
218
+ sys.exit(1)
219
+
220
+ elif args.command == 'info':
221
+ if args.remote:
222
+ # Eski remote info fonksiyonu
223
+ success, message = show_package_info(args.app_name, args.remote)
224
+ if not success:
225
+ print(f"❌ {message}")
226
+ sys.exit(1)
227
+ else:
228
+ # Yeni detaylı info komutu
229
+ success = show_app_info(args.app_name)
230
+ sys.exit(0 if success else 1)
231
+
232
+ elif args.command == 'validate':
233
+ success = validate_app_folder(args.folder)
234
+ sys.exit(0 if success else 1)
235
+
236
+ elif args.command == 'publish':
237
+ # Yeni publish komutu
238
+ success, message = publish_app(args.app_path, push_to_github=args.push)
239
+ if not success:
240
+ print(f"❌ {message}")
241
+ sys.exit(1)
242
+
243
+ elif args.command == 'remote':
244
+ output = list_remote_packages(args.details)
245
+ print(output)
246
+
247
+ elif args.command == 'health':
248
+ check_system_health()
249
+
250
+ elif args.command == 'check-env':
251
+ success = run_environment_check()
252
+ sys.exit(0 if success else 1)
253
+
254
+ elif args.command == 'doctor':
255
+ success = run_doctor()
256
+ sys.exit(0 if success else 1)
257
+
258
+ elif args.command == 'clean':
259
+ success = run_clean(args.dry_run)
260
+ sys.exit(0 if success else 1)
261
+
262
+ elif args.command == 'where':
263
+ if args.app_name:
264
+ if args.open:
265
+ from where_command import open_app_location
266
+ success = open_app_location(args.app_name)
267
+ else:
268
+ success = locate_app_path(args.app_name, args.check_entry)
269
+ sys.exit(0 if success else 1)
270
+ else:
271
+ success = list_all_app_locations()
272
+ sys.exit(0 if success else 1)
273
+
274
+
275
+
276
+ elif args.command == 'version':
277
+ if args.short:
278
+ print_version("short")
279
+ elif args.json:
280
+ print_version("json")
281
+ elif args.detailed:
282
+ print_detailed_version()
283
+ else:
284
+ print_version("default")
285
+
286
+ except KeyboardInterrupt:
287
+ print("\n❌ İşlem iptal edildi")
288
+ sys.exit(1)
289
+ except Exception as e:
290
+ print(f"❌ Beklenmeyen hata: {e}")
291
+ sys.exit(1)
292
+
293
+ if __name__ == '__main__':
294
+ main()
manifest_schema.py ADDED
@@ -0,0 +1,84 @@
1
+ import json
2
+ import os
3
+
4
+ def load_manifest(manifest_path):
5
+ """
6
+ Manifest dosyasını yükler ve parse eder.
7
+
8
+ Args:
9
+ manifest_path (str): Manifest dosyasının yolu
10
+
11
+ Returns:
12
+ dict: Parse edilmiş manifest dictionary'si
13
+
14
+ Raises:
15
+ FileNotFoundError: Dosya bulunamadığında
16
+ json.JSONDecodeError: JSON parse hatası
17
+ """
18
+ if not os.path.exists(manifest_path):
19
+ raise FileNotFoundError(f"Manifest dosyası bulunamadı: {manifest_path}")
20
+
21
+ with open(manifest_path, 'r', encoding='utf-8') as f:
22
+ return json.load(f)
23
+
24
+ def validate_manifest(manifest):
25
+ """
26
+ Manifest dosyasının gerekli alanları içerip içermediğini ve tiplerinin doğru olup olmadığını kontrol eder.
27
+
28
+ Args:
29
+ manifest (dict): Doğrulanacak manifest dictionary'si
30
+
31
+ Returns:
32
+ bool: Manifest geçerliyse True, değilse False
33
+ """
34
+ # Gerekli alanlar
35
+ required_fields = {
36
+ 'name': str,
37
+ 'version': str,
38
+ 'language': str,
39
+ 'entry': str
40
+ }
41
+
42
+ # Opsiyonel alanlar
43
+ optional_fields = {
44
+ 'description': str,
45
+ 'dependencies': list
46
+ }
47
+
48
+ # Gerekli alanları kontrol et
49
+ for field, expected_type in required_fields.items():
50
+ if field not in manifest:
51
+ return False
52
+ if not isinstance(manifest[field], expected_type):
53
+ return False
54
+
55
+ # Dil kontrolü
56
+ if manifest['language'] not in ['python', 'lua']:
57
+ return False
58
+
59
+ # Opsiyonel alanları kontrol et (varsa)
60
+ for field, expected_type in optional_fields.items():
61
+ if field in manifest and not isinstance(manifest[field], expected_type):
62
+ return False
63
+
64
+ return True
65
+
66
+ def get_schema():
67
+ """
68
+ Manifest şemasını döndürür.
69
+
70
+ Returns:
71
+ dict: Manifest şeması
72
+ """
73
+ return {
74
+ "required_fields": {
75
+ "name": "string",
76
+ "version": "string",
77
+ "language": "string (python or lua)",
78
+ "entry": "string"
79
+ },
80
+ "optional_fields": {
81
+ "description": "string",
82
+ "dependencies": "list"
83
+ }
84
+ }
manifest_validator.py ADDED
@@ -0,0 +1,245 @@
1
+ from manifest_schema import validate_manifest, get_schema
2
+
3
+ def validate_manifest_verbose(manifest):
4
+ """
5
+ Manifest dosyasını doğrular ve detaylı hata mesajları döndürür.
6
+
7
+ Args:
8
+ manifest (dict): Doğrulanacak manifest dictionary'si
9
+
10
+ Returns:
11
+ tuple: (is_valid: bool, errors: list of strings)
12
+ """
13
+ errors = []
14
+
15
+ if not isinstance(manifest, dict):
16
+ return False, ["Manifest geçerli bir JSON objesi değil"]
17
+
18
+ # Şema bilgilerini al
19
+ schema = get_schema()
20
+ required_fields = schema["required_fields"]
21
+
22
+ # Gerekli alanları kontrol et
23
+ for field, field_type in required_fields.items():
24
+ if field not in manifest:
25
+ errors.append(f"Gerekli alan eksik: '{field}'")
26
+ continue
27
+
28
+ # Tip kontrolü
29
+ value = manifest[field]
30
+
31
+ if field == "name":
32
+ if not isinstance(value, str) or not value.strip():
33
+ errors.append(f"'{field}' alanı boş olmayan bir string olmalı")
34
+ elif field == "version":
35
+ if not isinstance(value, str) or not value.strip():
36
+ errors.append(f"'{field}' alanı boş olmayan bir string olmalı")
37
+ elif not is_valid_version(value):
38
+ errors.append(f"'{field}' alanı geçerli bir sürüm formatında olmalı (örn: 1.0.0)")
39
+ elif field == "language":
40
+ if not isinstance(value, str):
41
+ errors.append(f"'{field}' alanı string olmalı")
42
+ elif value.lower() not in ["python", "lua"]:
43
+ errors.append(f"'{field}' alanı 'python' veya 'lua' olmalı, '{value}' geçersiz")
44
+ elif field == "entry":
45
+ if not isinstance(value, str) or not value.strip():
46
+ errors.append(f"'{field}' alanı boş olmayan bir string olmalı")
47
+ elif not is_valid_filename(value):
48
+ errors.append(f"'{field}' alanı geçerli bir dosya adı olmalı")
49
+
50
+ # Opsiyonel alanları kontrol et
51
+ if "description" in manifest:
52
+ if not isinstance(manifest["description"], str):
53
+ errors.append("'description' alanı string olmalı")
54
+
55
+ if "dependencies" in manifest:
56
+ if not isinstance(manifest["dependencies"], list):
57
+ errors.append("'dependencies' alanı liste olmalı")
58
+ else:
59
+ for i, dep in enumerate(manifest["dependencies"]):
60
+ if not isinstance(dep, str) or not dep.strip():
61
+ errors.append(f"'dependencies[{i}]' boş olmayan bir string olmalı")
62
+
63
+ # Bilinmeyen alanları kontrol et
64
+ known_fields = set(required_fields.keys()) | {"description", "dependencies"}
65
+ for field in manifest.keys():
66
+ if field not in known_fields:
67
+ errors.append(f"Bilinmeyen alan: '{field}' (göz ardı edilecek)")
68
+
69
+ return len(errors) == 0, errors
70
+
71
+ def is_valid_version(version_string):
72
+ """
73
+ Sürüm string'inin geçerli olup olmadığını kontrol eder.
74
+
75
+ Args:
76
+ version_string (str): Sürüm string'i
77
+
78
+ Returns:
79
+ bool: Geçerliyse True
80
+ """
81
+ try:
82
+ # Basit sürüm formatı kontrolü (x.y.z veya x.y)
83
+ parts = version_string.split('.')
84
+ if len(parts) < 2 or len(parts) > 3:
85
+ return False
86
+
87
+ for part in parts:
88
+ if not part.isdigit():
89
+ return False
90
+
91
+ return True
92
+ except:
93
+ return False
94
+
95
+ def is_valid_filename(filename):
96
+ """
97
+ Dosya adının geçerli olup olmadığını kontrol eder.
98
+
99
+ Args:
100
+ filename (str): Dosya adı
101
+
102
+ Returns:
103
+ bool: Geçerliyse True
104
+ """
105
+ import os
106
+
107
+ # Boş string kontrolü
108
+ if not filename or not filename.strip():
109
+ return False
110
+
111
+ # Geçersiz karakterler
112
+ invalid_chars = ['<', '>', ':', '"', '|', '?', '*', '\0']
113
+ for char in invalid_chars:
114
+ if char in filename:
115
+ return False
116
+
117
+ # Sistem dosya adları (Windows)
118
+ reserved_names = [
119
+ 'CON', 'PRN', 'AUX', 'NUL',
120
+ 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
121
+ 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
122
+ ]
123
+
124
+ name_without_ext = os.path.splitext(filename)[0].upper()
125
+ if name_without_ext in reserved_names:
126
+ return False
127
+
128
+ return True
129
+
130
+ def validate_manifest_file(manifest_path):
131
+ """
132
+ Manifest dosyasını doğrular.
133
+
134
+ Args:
135
+ manifest_path (str): Manifest dosyasının yolu
136
+
137
+ Returns:
138
+ tuple: (is_valid: bool, errors: list of strings)
139
+ """
140
+ import json
141
+ import os
142
+
143
+ # Dosya varlığını kontrol et
144
+ if not os.path.exists(manifest_path):
145
+ return False, [f"Manifest dosyası bulunamadı: {manifest_path}"]
146
+
147
+ # JSON dosyasını yüklemeye çalış
148
+ try:
149
+ with open(manifest_path, 'r', encoding='utf-8') as f:
150
+ manifest = json.load(f)
151
+ except json.JSONDecodeError as e:
152
+ return False, [f"JSON formatı hatalı: {e}"]
153
+ except Exception as e:
154
+ return False, [f"Dosya okuma hatası: {e}"]
155
+
156
+ # Manifest içeriğini doğrula
157
+ return validate_manifest_verbose(manifest)
158
+
159
+ def get_validation_summary(errors):
160
+ """
161
+ Doğrulama hatalarının özetini döndürür.
162
+
163
+ Args:
164
+ errors (list): Hata mesajları listesi
165
+
166
+ Returns:
167
+ str: Hata özeti
168
+ """
169
+ if not errors:
170
+ return "✅ Manifest dosyası geçerli"
171
+
172
+ summary = f"❌ {len(errors)} hata bulundu:\n"
173
+ for i, error in enumerate(errors, 1):
174
+ summary += f"{i}. {error}\n"
175
+
176
+ return summary
177
+
178
+ def suggest_fixes(errors):
179
+ """
180
+ Hatalara göre düzeltme önerileri sunar.
181
+
182
+ Args:
183
+ errors (list): Hata mesajları listesi
184
+
185
+ Returns:
186
+ list: Düzeltme önerileri
187
+ """
188
+ suggestions = []
189
+
190
+ for error in errors:
191
+ if "Gerekli alan eksik" in error:
192
+ field = error.split("'")[1]
193
+ if field == "name":
194
+ suggestions.append("Uygulama adını 'name' alanına ekleyin")
195
+ elif field == "version":
196
+ suggestions.append("Sürüm bilgisini 'version' alanına ekleyin (örn: '1.0.0')")
197
+ elif field == "language":
198
+ suggestions.append("Programlama dilini 'language' alanına ekleyin ('python' veya 'lua')")
199
+ elif field == "entry":
200
+ suggestions.append("Giriş dosyasını 'entry' alanına ekleyin (örn: 'main.py')")
201
+
202
+ elif "geçerli bir sürüm formatında olmalı" in error:
203
+ suggestions.append("Sürüm formatını düzeltin (örn: '1.0.0', '2.1.5')")
204
+
205
+ elif "python' veya 'lua' olmalı" in error:
206
+ suggestions.append("Desteklenen dil kullanın: 'python' veya 'lua'")
207
+
208
+ elif "geçerli bir dosya adı olmalı" in error:
209
+ suggestions.append("Giriş dosyası adını düzeltin (geçersiz karakterler içermemeli)")
210
+
211
+ return suggestions
212
+
213
+ if __name__ == "__main__":
214
+ # Test için örnek manifest'ler
215
+
216
+ # Geçerli manifest
217
+ valid_manifest = {
218
+ "name": "test-app",
219
+ "version": "1.0.0",
220
+ "language": "python",
221
+ "entry": "main.py",
222
+ "description": "Test uygulaması"
223
+ }
224
+
225
+ # Geçersiz manifest
226
+ invalid_manifest = {
227
+ "name": "",
228
+ "version": "abc",
229
+ "language": "javascript",
230
+ "entry": "main.py",
231
+ "unknown_field": "value"
232
+ }
233
+
234
+ print("Geçerli manifest testi:")
235
+ is_valid, errors = validate_manifest_verbose(valid_manifest)
236
+ print(get_validation_summary(errors))
237
+
238
+ print("\nGeçersiz manifest testi:")
239
+ is_valid, errors = validate_manifest_verbose(invalid_manifest)
240
+ print(get_validation_summary(errors))
241
+
242
+ print("\nDüzeltme önerileri:")
243
+ suggestions = suggest_fixes(errors)
244
+ for suggestion in suggestions:
245
+ print(f"- {suggestion}")