Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude pattern hack #51

Open
duzun opened this issue Feb 7, 2016 · 8 comments
Open

Exclude pattern hack #51

duzun opened this issue Feb 7, 2016 · 8 comments

Comments

@duzun
Copy link

duzun commented Feb 7, 2016

I've wrote a function to simplify writing exclude pattern, due to the fact that ** matches all children and the parent.

del.sync(extendNegGlobs(['public/assets/**', '!public/assets/goat.png']));
// is equivalent with 
del.sync(['public/assets/**', '!public/assets/goat.png', '!public/assets', '!public']);

Here is my function:

function extendNegGlobs(arr) {
    var ext = [];
    var negs = {};
    arr.forEach((g, i) => {
        if ( g.slice(0,1) == '!' ) {
            negs[g] = i;
        }
    });
    Object.keys(negs).forEach((g) => {
        var d;
        if ( g.slice(-1) == '*' ) do {
            g = path.dirname(d = g);
            if ( g == '!' || g == '.' || g == d ) break;
            if ( !(g in negs) ) {
                negs[g] = ext.push(g);
            }
        }
        while ( true );
    });
    return arr.concat(ext);
}

I don't pretend this is a complete/nice solution, but it might be a starting point to finding one!

Comments ?

@ericmdantas
Copy link

Worked for me, thanks!

@ericmdantas
Copy link

ericmdantas commented Aug 26, 2016

Why don't you open a PR where you'd introduce a new option to do that under the hood?

@duzun
Copy link
Author

duzun commented Aug 26, 2016

Here is a note from readme.md:

Beware

The glob pattern ** matches all children and the parent.

So this won't work:

del.sync(['public/assets/**', '!public/assets/goat.png']);

You have to explicitly ignore the parent directories too:

del.sync(['public/assets/**', '!public/assets', '!public/assets/goat.png']);

Suggestions on how to improve this welcome!

So I just made a suggestion.
This could be implemented internally and I think it would be ok to have this as the default behavior.

But no one has left a comment since :-(

@ericmdantas
Copy link

Well, we could always create a "plugin" that simply returns that function of yours and use it with del, just like in your example.

@schnittstabil
Copy link
Collaborator

schnittstabil commented Aug 26, 2016

To be honest, I haven't commented yet, because I can't imagine how we could extend that idea to solve all variants of the problem in a maintainable way.

Some notes about the syntax from node-glob:

  • [...] Matches a range of characters, similar to a RegExp range. If the first character of the range is ! or ^ then it matches any character not in the range.
  • !(pattern|pattern|pattern) Matches anything that does not match any of the patterns provided.
  • ?(pattern|pattern|pattern) Matches zero or one occurrence of the patterns provided.
  • +(pattern|pattern|pattern) Matches one or more occurrences of the patterns provided.
    *(a|b|c) Matches zero or more occurrences of the patterns provided
    @(pattern|pat*|pat?erN) Matches exactly one of the patterns provided

Thus there are some expressions to deal with:

  • '(public|private)/+(assets)/**'
  • 'public/assets/**/**'
  • … and many more 😒

@duzun
Copy link
Author

duzun commented Aug 27, 2016

I think a call like del.sync(['public/assets/**', '!public/assets/goat.png']); should remove all files inside public/assets/ except public/assets/goat.png file.
The intention is clear in the pattern, but the behavior is not doing what "is obvious".

The intention of my hack was to make the "obvious" thing happen, but I agree it is not universal and only works with simple patterns.

The universal solution would be to make del not remove folders that contain at least one file that matches an exclude pattern.

The issue lays in the implementation:
del gets a files & folders list using globby and then removes these files and folders. But at this point exclude patterns are already applied, and the list might contains folders of excluded files, thus folders get removed together with their files.

I think the algo should be changed if we want to solve this issue.
If my understanding of glob is right, there is only one pattern that excludes files (and folders) from previous patterns, and it starts with "!".
So del should not remove any folder that contains at least one file that matches any exclude pattern (in any subfolder).

@ibratoev
Copy link

ibratoev commented Nov 7, 2016

I find the current behavior confusing as well. What about making sure that after some files are whitelisted, their parent directories would not be deleted as well? Makes sense for a feature suggestion?

@tantv
Copy link

tantv commented Jun 9, 2017

Hi @duzun,

I have the problems with the nested folder and how can apply your solution for this problem or we have another solution for this.

Structure:

Test folder
---- A folder
---- B folder
---- Resource folder
---- ---- assets folder
---- ---- ---- css folder
---- ---- ---- tools folder
---- ---- ---- ---- node_modules
---- ---- ---- ---- bower_components

How can I delete the Test folder without delete the node & bower folder.

My setting doesn't work

gulp.task('clean', function () {
        return del([
            'Test/**/*',
            'Test/'
            '!Test/Resource/',
            '!Test/Resource/**',
            '!Test/Resource/assets/',
            '!Test/Resource/assets/**',
            '!Test/Resource/assets/tools/',
            '!Test/Resource/assets/tools/**'
        ], {force: true});
});

Thanks,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants