gulpjs / glob-stream

Readable streamx interface over anymatch.
MIT License
178 stars 53 forks source link

Add an option to enable globs coming in the order they were passed in #7

Closed yocontra closed 10 years ago

yocontra commented 10 years ago

cc @lazd

azweb76 commented 10 years ago

They are being returned in the order passed in. The first glob is being excluded because the path does not exist. Should "key" be "hey" in the following... "./fixtures/whatsgoingon/key/isaidhey/whatsgoingon/test.txt"?

yocontra commented 10 years ago

@azweb76 Probably. Currently they should not be coming back in the order passed in. If they are then something in node-glob is blocking

lazd commented 10 years ago

@azweb76, yes, that's an error in the test

yocontra commented 10 years ago

I corrected the test and I'm having trouble getting things to come out of order. The only explanation I can think of is that combine-stream is ordering the streams it combines but that seems unlikely. We might have to create a more complex dir structure for the "slow" glob in the test

armed commented 10 years ago

Is it ok, when this test fail? I've an issue with it in my current project.

it('should return a correctly ordered file name stream for three globs', function(done) {
  var globArray = [
    join(__dirname, "./fixtures/**/test.txt"),
    join(__dirname, "./fixtures/**/test.coffee"),
    join(__dirname, "./fixtures/**/test.js")
  ];
  var stream = gs.create(globArray, {cwd: __dirname});

  var files = [];
  stream.on('error', done);
  stream.on('data', function(file) {
    should.exist(file);
    should.exist(file.path);
    files.push(file);
  });
  stream.on('end', function() {
    files.length.should.equal(3);
    path.basename(files[0].path).should.equal('test.txt');
    path.basename(files[1].path).should.equal('test.coffee');
    path.basename(files[2].path).should.equal('test.js');
    done();
  });
});
yocontra commented 10 years ago

@armed Does that fail? If so this is a bug

armed commented 10 years ago

Yes, it fails. At least on my machine. I modified already existing test case: https://github.com/wearefractal/glob-stream/blob/master/test/main.js#L212

armed commented 10 years ago

It started failing when I changed full paths to paths with globstars.

yocontra commented 10 years ago

@armed Awesome I was having issues making the test fail for ordering. I'll fix them up and start working on this again

armed commented 10 years ago

@Contra great news! This fix is a show stopper for my current grunt -> gulp migration.

armed commented 10 years ago

@Contra I've been experimenting with ordering of streams. I created drop-in replacement for combine-stream which preserves ordering. It passes all tests in glob-stream master plus test which I posted above. Code may be ugly, but I've managed to build all assets in my projects without any issues.

This is what I got (maybe it will help):

var Readable = require('stream').Readable;
var util = require('util');

function OrderedStreams(options) {
  options = options || {};
  if (Array.isArray(options)) {
    options = {streams: options};
  }
  options.objectMode = true;

  Readable.call(this, options);

  var streams = options.streams || [];
  var self = this;

  if (streams.length === 0) {
    this.push(null); // no streams, close
  } else {
    // initial index in list of glob-streams
    this._currentIndex = 0;
    this._buff = {};
    this._openedStreams = streams.length;
    streams.forEach(function (s, i) {
      s.on('data', function (data) {
        // if data emmitted from stream, which is at current index
        if (i === self._currentIndex) {
          self._currentIndex++;
          self.push(data); // push data downstream
        } else {
          self._buff[i] = data; // or store in buffer for future
        }
      });
      s.on('end', function () {
        // if stream ended without any data and it at current index
        if (i === self._currentIndex) {
          self._currentIndex++; // increment index
        }
        if (!--self._openedStreams) {
          self.push(null); // close OrderedStreams
        }
      })
      s.on('error', function (e) {
        self.emit('error', e); // error event downstream
      })
    });

    this.on('finish', function() {
      streams.forEach(function (s) {
        s.end();
      });
    });
  }
}

util.inherits(OrderedStreams, Readable);

OrderedStreams.prototype._read = function () {
  // if we already have stored data push it
  var data = this._buff[this._currentIndex];
  if (data) {
    this._currentIndex++;
    this.push(data);
  }
}

module.exports = OrderedStreams;
yocontra commented 10 years ago

@armed got a repo so I can look over the code and the tests?

armed commented 10 years ago

@Contra https://github.com/armed/glob-stream, added it in root for convenience.

yocontra commented 10 years ago

@armed the combined-stream should be in its own package with full test coverage not included in the glob-stream package

armed commented 10 years ago

@Contra I wasn't planning to leave it in glob-stream, it's just experiments. If that combine-stream implementation is ok, then I create package.

armed commented 10 years ago

@Contra I created package for ordered stream implementation, glob-stream repo with this package is here: https://github.com/armed/glob-stream

rschmukler commented 10 years ago

@armed, @contra

I ran into something similar and ended up writing stream-series. You can use it like the following:

  return series(
    gulp.src(['lib/{components,pages}/**/index.js']),
    gulp.src(['lib/{components,pages}/**/*.js', '!lib/{components,pages}/**/index.js'])
  )
  .pipe(concat('build.js'))
  .pipe(gulp.dest('public/'))
yocontra commented 10 years ago

@rschmukler Does the latest glob-stream solve this for you? npm update should pull it in

yocontra commented 10 years ago
 return gulp.src(['lib/{components,pages}/**/index.js', 'lib/{components,pages}/**/*.js', '!lib/{components,pages}/**/index.js'])
  .pipe(concat('build.js'))
  .pipe(gulp.dest('public/'))

should work fine now

rschmukler commented 10 years ago

Ah, I am using gulp 3.4.0 which imports vinyl-fs 0.0.1, which I am guessing does not have the latest glob-stream?

I was still running into the issue but maybe I'm screwing something up...

yocontra commented 10 years ago

@rschmukler npm update will update the whole tree. vinyl-fs hasn't updated but it uses a semver range for glob-stream so any bug fixes to glob-stream won't require me to update the whole tree above it

rschmukler commented 10 years ago

Ah woops. Thanks @Contra !