@@ -4,6 +4,8 @@ import 'dart:io';
4
4
import 'package:archive/archive_io.dart' ;
5
5
import 'package:args/command_runner.dart' ;
6
6
import 'package:crypto/crypto.dart' ;
7
+ import 'package:glob/glob.dart' ;
8
+ import 'package:glob/list_local_fs.dart' ;
7
9
import 'package:http/http.dart' as http;
8
10
import 'package:path/path.dart' as path;
9
11
import 'package:shelf/shelf.dart' ;
@@ -58,11 +60,24 @@ const platforms = {
58
60
}
59
61
};
60
62
61
- const junkFileExtensionsDesktop = [".c" , ".h" , ".hpp" , ".typed" , ".a" , ".pdb" ];
62
- const junkFileExtensionsMobile = [...junkFileExtensionsDesktop, ".exe" , ".dll" ];
63
-
64
- const junkFilesDesktop = ["__pycache__" ];
65
- const junkFilesMobile = [...junkFilesDesktop, "bin" ];
63
+ final dartFile = Glob ("**.dart" );
64
+
65
+ const junkFilesDesktop = [
66
+ "**.c" ,
67
+ "**.h" ,
68
+ "**.cpp" ,
69
+ "**.hpp" ,
70
+ "**.typed" ,
71
+ "**.a" ,
72
+ "**.pdb" ,
73
+ "**.pyi" ,
74
+ "**.pxd" ,
75
+ "**.pyx" ,
76
+ "**/LICENSE" ,
77
+ "**.dist-info" ,
78
+ "**/__pycache__" ,
79
+ ];
80
+ const junkFilesMobile = [...junkFilesDesktop, "**.exe" , "**.dll" , "**/bin" ];
66
81
67
82
class PackageCommand extends Command {
68
83
bool _verbose = false ;
@@ -104,6 +119,16 @@ class PackageCommand extends Command {
104
119
help:
105
120
"Cleanup app and packages from unneccessary files and directories." ,
106
121
negatable: false );
122
+ argParser.addFlag ("cleanup-app" ,
123
+ help: "Cleanup app from unneccessary files and directories." ,
124
+ negatable: false );
125
+ argParser.addMultiOption ('cleanup-app-files' ,
126
+ help: "List of globs to delete extra app files and directories." );
127
+ argParser.addFlag ("cleanup-packages" ,
128
+ help: "Cleanup packages from unneccessary files and directories." ,
129
+ negatable: false );
130
+ argParser.addMultiOption ('cleanup-packages-files' ,
131
+ help: "List of globs to delete extra packages files and directories." );
107
132
argParser.addFlag ("verbose" , help: "Verbose output." , negatable: false );
108
133
}
109
134
@@ -135,6 +160,10 @@ class PackageCommand extends Command {
135
160
bool compileApp = argResults? ["compile-app" ];
136
161
bool compilePackages = argResults? ["compile-packages" ];
137
162
bool cleanup = argResults? ["cleanup" ];
163
+ bool cleanupApp = argResults? ["cleanup-app" ];
164
+ List <String > cleanupAppFiles = argResults? ['cleanup-app-files' ];
165
+ bool cleanupPackages = argResults? ["cleanup-packages" ];
166
+ List <String > cleanupPackagesFiles = argResults? ['cleanup-packages-files' ];
138
167
_verbose = argResults? ["verbose" ];
139
168
140
169
if (path.isRelative (sourceDirPath)) {
@@ -162,8 +191,6 @@ class PackageCommand extends Command {
162
191
bool isMobile = (platform == "iOS" || platform == "Android" );
163
192
bool isWeb = platform == "Pyodide" ;
164
193
165
- var junkFileExtensions =
166
- isMobile ? junkFileExtensionsMobile : junkFileExtensionsDesktop;
167
194
var junkFiles = isMobile ? junkFilesMobile : junkFilesDesktop;
168
195
169
196
// Extra indexs
@@ -212,19 +239,19 @@ class PackageCommand extends Command {
212
239
await runPython (['-m' , 'compileall' , '-b' , tempDir.path]);
213
240
214
241
verbose ("Deleting original .py files" );
215
- await cleanupPyPackages (tempDir, [".py" ], [ ]);
242
+ await cleanupDir (tempDir, ["** .py" ]);
216
243
}
217
244
218
245
// cleanup
219
- if (cleanup) {
246
+ if (cleanupApp || cleanup) {
247
+ var allJunkFiles = [...junkFiles, ...cleanupAppFiles];
220
248
if (_verbose) {
221
249
verbose (
222
- "Delete unnecessary app files with extensions: $junkFileExtensions " );
223
- verbose ("Delete unnecessary app files and directories: $junkFiles " );
250
+ "Delete unnecessary app files and directories: $allJunkFiles " );
224
251
} else {
225
252
stdout.writeln (("Cleanup app" ));
226
253
}
227
- await cleanupPyPackages (tempDir, junkFileExtensions, junkFiles );
254
+ await cleanupDir (tempDir, allJunkFiles );
228
255
}
229
256
230
257
// install requirements
@@ -358,21 +385,19 @@ class PackageCommand extends Command {
358
385
await runPython (['-m' , 'compileall' , '-b' , sitePackagesDir]);
359
386
360
387
verbose ("Deleting original .py files" );
361
- await cleanupPyPackages (Directory (sitePackagesDir), [".py" ], [ ]);
388
+ await cleanupDir (Directory (sitePackagesDir), ["** .py" ]);
362
389
}
363
390
364
391
// cleanup packages
365
- if (cleanup) {
392
+ if (cleanupPackages || cleanup) {
393
+ var allJunkFiles = [...junkFiles, ...cleanupPackagesFiles];
366
394
if (_verbose) {
367
395
verbose (
368
- "Delete unnecessary package files with extensions: $junkFileExtensions " );
369
- verbose (
370
- "Delete unnecessary package files and directories: $junkFiles " );
396
+ "Delete unnecessary package files and directories: $allJunkFiles " );
371
397
} else {
372
398
stdout.writeln (("Cleanup installed packages" ));
373
399
}
374
- await cleanupPyPackages (
375
- Directory (sitePackagesDir), junkFileExtensions, junkFiles);
400
+ await cleanupDir (Directory (sitePackagesDir), allJunkFiles);
376
401
}
377
402
} finally {
378
403
if (sitecustomizeDir != null && await sitecustomizeDir.exists ()) {
@@ -435,26 +460,20 @@ class PackageCommand extends Command {
435
460
}
436
461
}
437
462
438
- Future <void > cleanupPyPackages (Directory directory,
439
- List <String > fileExtensions, List <String > filesAndDirectories) async {
440
- await for (var entity in directory.list ()) {
441
- if (entity is Directory ) {
442
- await cleanupPyPackages (entity, fileExtensions, filesAndDirectories);
443
- } else if (entity is File &&
444
- (fileExtensions.contains (path.extension (entity.path)) ||
445
- filesAndDirectories.contains (path.basename (entity.path)))) {
446
- verbose ("Deleting ${entity .path }" );
447
-
448
- await entity.delete ();
449
- }
450
- }
463
+ Future <void > cleanupDir (Directory directory, List <String > filesGlobs) async {
464
+ return cleanupDirRecursive (
465
+ directory, filesGlobs.map ((g) => Glob (g.replaceAll ("\\ " , "/" ))));
466
+ }
451
467
452
- await for (var entity in directory.list ()) {
453
- if (entity is Directory &&
454
- filesAndDirectories.contains (path.basename (entity.path))) {
468
+ Future <void > cleanupDirRecursive (
469
+ Directory directory, Iterable <Glob > globs) async {
470
+ for (var entity in directory.listSync ()) {
471
+ if (globs.any ((g) => g.matches (entity.path.replaceAll ("\\ " , "/" ))) &&
472
+ await entity.exists ()) {
455
473
verbose ("Deleting ${entity .path }" );
456
-
457
474
await entity.delete (recursive: true );
475
+ } else if (entity is Directory ) {
476
+ await cleanupDirRecursive (entity, globs);
458
477
}
459
478
}
460
479
}
@@ -533,7 +552,7 @@ class PackageCommand extends Command {
533
552
'tar' , ['-xzf' , pythonArchivePath, '-C' , _pythonDir! .path]);
534
553
535
554
if (Platform .isMacOS) {
536
- copySysconfigFiles (_pythonDir! .path);
555
+ duplicateSysconfigFile (_pythonDir! .path);
537
556
}
538
557
}
539
558
}
@@ -547,53 +566,23 @@ class PackageCommand extends Command {
547
566
return await runExec (pythonExePath, args, environment: environment);
548
567
}
549
568
550
- void copySysconfigFiles (String pythonDir) {
551
- final libPath = Directory (path.join (pythonDir, "python" , "lib" ));
552
-
553
- // Find the Python version dynamically (e.g., python3.10, python3.11)
554
- if (! libPath.existsSync ()) {
555
- stderr.writeln ('Python lib directory not found: $libPath ' );
556
- exit (1 );
557
- }
558
-
559
- // Find the actual Python 3.x subdirectory
560
- final pythonSubDir = libPath
561
- .listSync ()
562
- .whereType <Directory >()
563
- .firstWhere ((dir) => RegExp (r'python3\.\d+' ).hasMatch (dir.path),
564
- orElse: () => throw Exception ('No Python 3.x directory found' ))
565
- .path;
566
-
567
- final targetDir = Directory (pythonSubDir);
568
-
569
- // Search for `_sysconfigdata__*.py` files
570
- final files = targetDir
571
- .listSync ()
572
- .whereType <File >()
573
- .where ((file) => RegExp (r'_sysconfigdata__.*\.py$' ).hasMatch (file.path))
574
- .toList ();
575
-
576
- if (files.isEmpty) {
577
- stderr.writeln ('No matching _sysconfigdata__ files found in $targetDir ' );
578
- exit (1 );
579
- }
580
-
581
- for (final file in files) {
582
- final dir = file.parent.path;
583
-
584
- // Define the new filenames
585
- final targets = [
586
- '_sysconfigdata__darwin_arm64_iphoneos.py' ,
587
- '_sysconfigdata__darwin_arm64_iphonesimulator.py' ,
588
- '_sysconfigdata__darwin_x86_64_iphonesimulator.py' ,
589
- ];
590
-
591
- for (final target in targets) {
592
- final targetPath = '$dir /$target ' ;
593
- file.copySync (targetPath);
594
- if (_verbose) {
595
- verbose ('Copied ${file .path } -> $targetPath ' );
569
+ void duplicateSysconfigFile (String pythonDir) {
570
+ final sysConfigGlob = Glob ("python/lib/python3.*/_sysconfigdata__*.py" );
571
+ for (var sysConfig in sysConfigGlob.listSync (root: pythonDir)) {
572
+ // copy the first found sys config and exit
573
+ if (sysConfig is File ) {
574
+ for (final target in [
575
+ '_sysconfigdata__darwin_arm64_iphoneos.py' ,
576
+ '_sysconfigdata__darwin_arm64_iphonesimulator.py' ,
577
+ '_sysconfigdata__darwin_x86_64_iphonesimulator.py' ,
578
+ ]) {
579
+ var targetPath = path.join (sysConfig.parent.path, target);
580
+ (sysConfig as File ).copySync (targetPath);
581
+ if (_verbose) {
582
+ verbose ('Copied ${sysConfig .path } -> $targetPath ' );
583
+ }
596
584
}
585
+ break ;
597
586
}
598
587
}
599
588
}
0 commit comments