11import 'dart:io' ;
22
33import 'package:archive/archive_io.dart' ;
4+ import 'package:get_it/get_it.dart' ;
45import 'package:glob/glob.dart' ;
6+ import 'package:mason_logger/mason_logger.dart' ;
57import 'package:path/path.dart' as p;
68import 'package:pool/pool.dart' ;
79
810/// Creates a zip archive of the given [directory] .
911Future <List <int >> zipDir (Directory directory) async {
12+ final logger = GetIt .I <Logger >();
13+
14+ logger.detail ('Archiving directory: ${directory .path }' );
15+
1016 // NOTE: We can't use p.join here due to https://github.com/dart-lang/path/issues/37
1117 // being present on Windows.
1218 final directoryPath = directory.path + p.separator;
@@ -23,48 +29,106 @@ Future<List<int>> zipDir(Directory directory) async {
2329
2430 for (final file in gitignoreFiles) {
2531 if (file.existsSync ()) {
32+ logger.detail ('Found .gitignore file: ${file .path }' );
2633 gitignores += '${await file .readAsString ()}\n ' ;
2734 }
2835 }
2936
30- final exclude = gitignores
37+ // Initialize two lists to hold exclusion and inclusion patterns
38+ final excludePatterns = < String > [];
39+ final includePatterns = < String > [];
40+
41+ gitignores
3142 .split ('\n ' )
3243 .where ((line) => line.isNotEmpty && ! line.startsWith ('#' ))
33- .map ((line) => line.startsWith ('/' ) ? line.substring (1 ) : line)
34- .map ((line) => '**$line **' )
35- .toList ();
44+ .forEach ((line) {
45+ // Check if the line is an inclusion pattern (negation pattern)
46+ final isInclusionPattern = line.startsWith ('!' );
47+
48+ if (isInclusionPattern) {
49+ // Remove the leading '!' and process the line
50+ line = line.substring (1 );
51+ }
52+
53+ // Process directory patterns by adding `**/` at the start if not already rooted and `/**` at the end
54+ final isDirectory = line.endsWith ('/' );
55+
56+ // Remove leading `/` from the line if present.
57+ var processedLine = line.startsWith ('/' ) ? line.substring (1 ) : line;
58+
59+ if (isDirectory) {
60+ // If a directory, prepend with `**/` and append with `/**` if it doesn't end with `/`.
61+ processedLine =
62+ "**/$processedLine ${processedLine .endsWith ('/' ) ? '' : '/**' }" ;
63+ } else {
64+ // For files, add `**/` at the start unless the pattern already starts with a specific directory
65+ processedLine = '**/$processedLine ' ;
66+ }
67+
68+ // Add the processed line to the appropriate list
69+ if (isInclusionPattern) {
70+ includePatterns.add (processedLine);
71+ } else {
72+ excludePatterns.add (processedLine);
73+ }
74+ });
3675
3776 // Exclude common files.
38- exclude .addAll ([
39- '**.map' ,
40- '**.git**' ,
41- '**.dart_tool**' ,
42- '**.packages** ' ,
43- '**.idea**' ,
44- '**.vscode**' ,
45- '**build**' ,
46- '**android**' ,
47- '**ios**' ,
48- '**linux**' ,
49- '**macos**' ,
50- '**windows**' ,
77+ excludePatterns .addAll ([
78+ '**/* .map' ,
79+ '**/ .git/ **' ,
80+ '**/ .dart_tool/ **' ,
81+ '**/ .packages' ,
82+ '**/ .idea/ **' ,
83+ '**/ .vscode/ **' ,
84+ '**/ build/ **' ,
85+ '**/ android/ **' ,
86+ '**/ ios/ **' ,
87+ '**/ linux/ **' ,
88+ '**/ macos/ **' ,
89+ '**/ windows/ **' ,
5190 ]);
5291
92+ logger.detail ('Excluding patterns: $excludePatterns ' );
93+ logger.detail ('Including patterns: $includePatterns ' );
94+
5395 final pool = Pool (10 );
5496
5597 Future <void > addEntityToArchive (FileSystemEntity entity) async {
5698 if (entity is ! File ) return ;
5799
58- // Exclude files that match the patterns in the `.gitignore` file.
59- for (final pattern in exclude) {
100+ // By default, don't exclude the entity.
101+ var excludeEntity = false ;
102+
103+ // Exclude files that match the patterns in the exclude list.
104+ for (final pattern in excludePatterns) {
60105 final glob = Glob (pattern);
61106 final match = glob.matches (entity.path.replaceFirst (directoryPath, '' ));
62-
63107 if (match) {
64- return ;
108+ excludeEntity = true ;
109+ break ;
110+ }
111+ }
112+
113+ // If the entity was marked for exclusion, check if it should be included again.
114+ if (excludeEntity) {
115+ for (final pattern in includePatterns) {
116+ final glob = Glob (pattern);
117+ final match = glob.matches (entity.path.replaceFirst (directoryPath, '' ));
118+ if (match) {
119+ excludeEntity = false ;
120+ break ;
121+ }
65122 }
66123 }
67124
125+ // If excludeEntity is true after checking both lists, the entity should be excluded.
126+ if (excludeEntity) {
127+ logger.detail ('Excluding file from archiving: ${entity .path }' );
128+ return ; // Skip this entity, move to the next one
129+ }
130+
131+ // Archive the file
68132 await pool.withResource (() async {
69133 final length = await entity.length ();
70134 final bytes = await entity.readAsBytes ();
@@ -95,5 +159,7 @@ Future<List<int>> zipDir(Directory directory) async {
95159 throw Exception ('Failed to encode archive.' );
96160 }
97161
162+ logger.detail ('Archive size: ${encoded .length } bytes' );
163+
98164 return encoded;
99165}
0 commit comments