1
1
package pack
2
2
3
3
import (
4
+ "bufio"
5
+ "errors"
4
6
"fmt"
5
7
"io/fs"
6
8
"os"
@@ -33,6 +35,8 @@ const (
33
35
versionLuaFileName = "VERSION.lua"
34
36
35
37
rocksManifestPath = ".rocks/share/tarantool/rocks/manifest"
38
+
39
+ ignoreFile = ".packignore"
36
40
)
37
41
38
42
var (
@@ -157,6 +161,139 @@ func previousPackageFilters(packCtx *PackCtx) []func(
157
161
}
158
162
}
159
163
164
+ func ignorePatternToRegex (pattern string , ignoreLocation string ) (string , bool , bool ) {
165
+ onlyDirs := strings .HasSuffix (pattern , "/" )
166
+ if onlyDirs {
167
+ pattern = pattern [:len (pattern )- 1 ]
168
+ }
169
+
170
+ negate := false
171
+ if strings .HasPrefix (pattern , "!" ) {
172
+ negate = true
173
+ pattern = pattern [1 :]
174
+ } else {
175
+ if strings .HasPrefix (pattern , "\\ !" ) || strings .HasPrefix (pattern , "\\ #" ) {
176
+ pattern = pattern [1 :]
177
+ }
178
+ }
179
+
180
+ expr := pattern
181
+ expr = strings .ReplaceAll (expr , "/**/" , "/([^/]+/)*" )
182
+ // expr = strings.ReplaceAll(expr, "**/", "([^/]+/)*")
183
+ // expr = strings.ReplaceAll(expr, "/**", "[^/]*")
184
+ expr = strings .ReplaceAll (expr , "*" , "[^/]*" )
185
+ expr = strings .ReplaceAll (expr , "?" , "[^/]" )
186
+
187
+ if strings .HasPrefix (pattern , "/" ) {
188
+ expr = ignoreLocation + expr
189
+ } else {
190
+ expr = "/?([^/]+/)*" + expr
191
+ }
192
+
193
+ return expr , negate , onlyDirs
194
+ }
195
+
196
+ // ignoreFilter returns filter that excludes files based on the patterns.
197
+ func ignoreFilter (fsys fs.FS , ignoreFile string ) func (
198
+ srcInfo os.FileInfo , src string ) bool {
199
+ log .Infof ("ignoreFilter: %q" , ignoreFile )
200
+ ignoreFileDir := filepath .Dir (ignoreFile )
201
+
202
+ f , err := fsys .Open (ignoreFile )
203
+ if err != nil {
204
+ if ! errors .Is (err , fs .ErrNotExist ) {
205
+ log .Errorf ("Failed to open %q: %s" , ignoreFile , err .Error ())
206
+ }
207
+ return nil
208
+ }
209
+
210
+ defer f .Close ()
211
+
212
+ var exprExclude , exprInclude , exprExcludeDirs , exprIncludeDirs []string
213
+
214
+ s := bufio .NewScanner (f )
215
+ for s .Scan () {
216
+ pattern := strings .TrimSpace (s .Text ())
217
+ if pattern == "" || strings .HasPrefix (pattern , "#" ) {
218
+ continue
219
+ }
220
+
221
+ exprPart , negate , onlyDirs := ignorePatternToRegex (pattern , ignoreFileDir )
222
+ log .Infof ("exprPart: %q %v %v" , exprPart , negate , onlyDirs )
223
+
224
+ var expr * []string
225
+ if onlyDirs {
226
+ if negate {
227
+ expr = & exprIncludeDirs
228
+ } else {
229
+ expr = & exprExcludeDirs
230
+ }
231
+ } else {
232
+ if negate {
233
+ expr = & exprInclude
234
+ } else {
235
+ expr = & exprExclude
236
+ }
237
+ }
238
+ * expr = append (* expr , "(" + exprPart + ")" )
239
+ }
240
+
241
+ compileRegexp := func (expr []string ) * regexp.Regexp {
242
+ log .Infof ("compileRegexp: %v" , expr )
243
+ if len (expr ) == 0 {
244
+ return nil
245
+ }
246
+ re , err := regexp .Compile ("^" + strings .Join (expr , "|" ) + "$" )
247
+ if err != nil {
248
+ log .Infof (" failed to compile expression: %s" , err .Error ())
249
+ return nil
250
+ }
251
+ log .Infof (" expr=%s" , re .String ())
252
+ return re
253
+ }
254
+
255
+ reInclude := compileRegexp (exprInclude )
256
+ reExclude := compileRegexp (exprExclude )
257
+ reIncludeDirs := compileRegexp (exprIncludeDirs )
258
+ reExcludeDirs := compileRegexp (exprExcludeDirs )
259
+ // log.Infof("reInclude: %s", reInclude.String())
260
+ // log.Infof("reExclude: %s", reExclude.String())
261
+ // log.Infof("reIncludeDirs: %s", reIncludeDirs.String())
262
+ // log.Infof("reExcludeDirs: %s", reExcludeDirs.String())
263
+
264
+ return func (srcInfo os.FileInfo , src string ) bool {
265
+ log .Infof ("ignoreFilter(): %q" , src )
266
+
267
+ // Skip ignore file itself.
268
+ if filepath .Base (src ) == ignoreFile {
269
+ log .Infof (" } true (ignore file itself)" )
270
+ return true
271
+ }
272
+ // If it's directory first check patterns that only match directories.
273
+ if srcInfo .IsDir () {
274
+ log .Infof (" is dir" )
275
+ if reIncludeDirs != nil && reIncludeDirs .MatchString (src ) {
276
+ log .Infof (" } false (include dirs) %q" , reIncludeDirs .String ())
277
+ return false
278
+ }
279
+ if reExcludeDirs != nil && reExcludeDirs .MatchString (src ) {
280
+ log .Infof (" } true (exclude dirs) %q" , reExcludeDirs .String ())
281
+ return true
282
+ }
283
+ }
284
+ if reInclude != nil && reInclude .MatchString (src ) {
285
+ log .Infof (" } false (include) %q" , reInclude .String ())
286
+ return false
287
+ }
288
+ if reExclude != nil && reExclude .MatchString (src ) {
289
+ log .Infof (" } true (exclude) %q" , reExclude .String ())
290
+ return true
291
+ }
292
+ log .Infof (" } false" )
293
+ return false
294
+ }
295
+ }
296
+
160
297
// appSrcCopySkip returns a filter func to filter out artifacts paths.
161
298
func appSrcCopySkip (packCtx * PackCtx , cliOpts * config.CliOpts ,
162
299
srcAppPath string ) func (srcinfo os.FileInfo , src , dest string ) (bool , error ) {
@@ -166,13 +303,20 @@ func appSrcCopySkip(packCtx *PackCtx, cliOpts *config.CliOpts,
166
303
appCopyFilters = append (appCopyFilters , func (srcInfo os.FileInfo , src string ) bool {
167
304
return skipDefaults (srcInfo , src )
168
305
})
306
+ log .Infof ("appSrcCopySkip: srcAppPath: %q" , srcAppPath )
307
+ log .Infof ("appSrcCopySkip: ignoreFile: %q" , ignoreFile )
308
+ if f := ignoreFilter (os .DirFS (srcAppPath ), ignoreFile ); f != nil {
309
+ appCopyFilters = append (appCopyFilters , f )
310
+ }
169
311
170
312
return func (srcinfo os.FileInfo , src , dest string ) (bool , error ) {
171
313
for _ , shouldSkip := range appCopyFilters {
172
314
if shouldSkip (srcinfo , src ) {
315
+ log .Infof ("skip: %q > %q isDir=%v... SKIPPED" , src , dest , srcinfo .IsDir ())
173
316
return true , nil
174
317
}
175
318
}
319
+ log .Infof ("skip: %q > %q isDir=%v... COPIED" , src , dest , srcinfo .IsDir ())
176
320
return false , nil
177
321
}
178
322
}
0 commit comments