yeoman / generator

Rails-inspired generator system that provides scaffolding for your apps
http://yeoman.io
BSD 2-Clause "Simplified" License
1.21k stars 299 forks source link

Why is there a conflict when deleting and then copying new files? #891

Closed SimonHarte closed 8 years ago

SimonHarte commented 8 years ago

Don't exactly know if this is an issue with this project or mem-fs (or my code). It was already mentioned in another issue but didn't get quite the attention.

Scenario: I want to delete contents from a folder to then copy in new custom stuff, the folder and its contents were created with another generator, this fact should have no impact though.

Case 1: In my writing context I do this.fs.delete(this.destinationPath('**/*.*')) which successfully cleans directory contents without deleting the directories themselves, so far so good. I then execute this.fs.copy(this.templatePath('**'), this.destinationPath()), also in the writing context. I now get conflict messages for the files that should have already been removed which I have to confirm -> annoying.

Case 2: I clean up with the globbing pattern ** which also removes directories, now I get conflict messages for the directories I want to copy over instead of the files that are getting removed -> also annoying.

Note: Source and target file structures are the same.

Where's the culprit here? Do I simply take a bad approach? Do I have bad globbing patterns? Or are those conflicts just standard behaviour?

SBoudrias commented 8 years ago

mem-fs-editor is overwriting the deletion with a write action to a file, so it shows a conflict as it doesn't know the file was planned to be deleted.

That's quite a edge case, I'm not sure how we should handle that as Yeoman should not be destructive and warn when an existing file content will be modified.

Just to be clear, the files you're deleting are committed to disk?

SimonHarte commented 8 years ago

Yes, they were previously created with another generator. So there is no way I can force overwriting by any means, to suppress the message?

SBoudrias commented 8 years ago

No, you cannot delete a conflict message if you're overwriting the content of a file - that's what conflicting is for.

That being said, if you're combining multiple generators using composition, then there's no conflict if you overwrite a file in memory http://yeoman.io/authoring/composability.html

screendriver commented 8 years ago

I have the same issue. I create a Cordova project within my yeoman generator. It creates an index.html file in a directory www. Now I want to delete that automatic generated index.html with one that I wrote. If I make following I get a conflict as well:

this.fs.delete(this.destinationPath('www/index.html'));
this.fs.copy(
  this.templatePath('index.html'),
  this.destinationPath('www/index.html')
);
 conflict www/index.html
? Overwrite www/index.html? overwrite

I don't know how to solve this.

miguelsmuller commented 8 years ago

any news?

SBoudrias commented 8 years ago

Are you sure all the generators involved uses ONLY the new this.fs.X methods? If it doesn't then it won't work correctly.

miguelsmuller commented 8 years ago

yeoman: 1.8.5 yeoman-generator: 0.24.1

'use strict';

var util   = require('util')
  , path   = require('path')
  , git    = require('simple-git')()
  , yeoman = require('yeoman-generator');

module.exports = yeoman.Base.extend({
  constructor: function () {
    yeoman.Base.apply(this, arguments);
  },

  prompting: function() {
    this.log.writeln('\n→ INITIAL SETTINGS');

    return this.prompt([{
      type: 'input',
      name: 'projectName',
      message: 'Project name?',
      default: 'project'
    }]).then(function (bootAnswers) {
      this.bootAnswers = bootAnswers
    }.bind(this));
  },

  configuring: {
    cloneWordPress: function () {
      var done = this.async();

      this.log.writeln('\n→ INSTALLING');

      this.log.writeln('Please wait while WordPress is downloaded');

      git.outputHandler(function (command, stdout, stderr) {
        stdout.pipe(process.stdout);
        stderr.pipe(process.stderr);
      }).clone('git@github.com:WordPress/WordPress.git', this.bootAnswers.projectName, ['--depth', '1' ], function (response) {
        done(response);
      });

      this.destinationRoot(this.bootAnswers.projectName );
    },
  },

  writing: {
    removeFiles: function () {
      this.log.writeln('\n→ SETTING FILES');

    },
  },

  install: {

  },

  end: function() {
    this.fs.delete(this.destinationPath('.git/'));
    this.fs.delete(this.destinationPath('license.txt'));
    this.fs.delete(this.destinationPath('readme.html'));
    this.fs.delete(this.destinationPath('wp-config-sample.php'));

    this.log.writeln('\n→ SCAFFOLD COMPLETED');
  },
});
SBoudrias commented 8 years ago

Try moving the delete before the end loop. The files are getting written to disk prior to the end function, so relaunching a file writing phase will retrigger the conflict handler.

miguelsmuller commented 8 years ago

Sorry @SBoudrias , but I am Brazilian and my English is not the best ... I did not quite catch what you said.

I've put the delete inside at the end of configuring block, as well as put also block writing, install and end... all had the same result.

SBoudrias commented 8 years ago

@miguelsmuller so the two things that are wrong are:

  1. Deleting in the end loop happens after Yeoman ejected the previous mem-fs to disk. So it'll always throw a conflict.
  2. Your git plugin is doing hard write to the file system. This means Yeoman internal system doesn't handles those files and cannot know they are new. So it ask for conflicts. In this case I don't know what to tell you, maybe cache those files somewhere else and only copy those you need? That really depends on how the plugin you're using is working - and I can't really help you on that side.

The only thing you need to understand is for Yeoman to handle files properly as part of the conflict process, all files must go through mem-fs.

SBoudrias commented 8 years ago

Also, you might want to take a look at https://github.com/yeoman/yeoman-remote as a replacement for your git plugin.

screendriver commented 8 years ago

Are you sure all the generators involved uses ONLY the new this.fs.X methods?

Yes. I am only using this.fs.X methods.

miguelsmuller commented 8 years ago

I'll take a look at this option and see what I can solve. very much thanks for the help @SBoudrias