175

I am trying to stage a project from a working directory to a server (same machine). Using the following code:

gulp.src([
    'index.php',
    'css/**',
    'js/**',
    'src/**',
])
.pipe(gulp.dest('/var/www/'));

I would expect to see all the files copied. However it flattens the dir structure - all directories are copied but every file is placed in the root /var/www

Gulp seems like a great build tool but copying items should be a simple process surely?

M1ke
  • 5,739
  • 4
  • 24
  • 48
  • 10
    To any new viewers reading this question, it should be noted that the highest voted answer doesn't work to solve the original question specification of not flattening directories. It does solve problems people are having with not all the files _inside_ a directory from being copied, so that's useful! – M1ke Sep 11 '15 at 08:10
  • 2
    By not flattening, do you mean that you want 'css', 'js', and 'src' directories to be present in `/var/www/`? You could try `{css,js,src}/**/*` – Jason Goemaat May 14 '16 at 14:42
  • I know that glob expansion does work inside gulp, but I'd be confused if that worked differently to each item as an individual line in a list - as glob expansion is basically just intended to expand to a list before execution. – M1ke May 16 '16 at 12:03

4 Answers4

330

The following works without flattening the folder structure:

gulp.src(['input/folder/**/*']).pipe(gulp.dest('output/folder'));

The '**/*' is the important part. That expression is a glob which is a powerful file selection tool. For example, for copying only .js files use: 'input/folder/**/*.js'

cancerbero
  • 5,662
  • 1
  • 26
  • 18
  • 2
    think you forgot to add the gulp.dest. Should be ``.pipe(gulp.dest('output/folder'));`` – Matthew Sprankle Dec 16 '14 at 00:09
  • 3
    How do you do this with a specific file extension? – Chev Mar 19 '15 at 22:40
  • 2
    May you edit the answer to provide an example for the original set of files? I am unsure how this is _more_ appropriate but I'd be happy to look at how it works compared to the `{base:"."}` method. – M1ke Mar 26 '15 at 10:08
  • 1
    I have tested this for the original specified case and can confirm that altering the directory array line items from format `dir/**` to `dir/**/*` does not work; the files are still flattened into the `dest()` directory. – M1ke Jun 29 '15 at 10:29
  • 2
    It is important to note that the `base` default is "folder" as given in this answer. In other words, the base starts where the glob pattern begins. This helped me to understand where my files would end up and is also why you don't need the `**/*` in the `gulp.dest` parameter. Gulp takes everything in the glob and puts it in the dest folder with the same structure. – Neil Monroe Sep 22 '15 at 22:46
  • 4
    This doesn't fully answer the question being asked. It's a nice solution for how to correctly copy recursively, but it doesn't answer how to modify the base directory. – ty1824 Oct 01 '15 at 08:56
177

Turns out that to copy a complete directory structure gulp needs to be provided with a base for your gulp.src() method.

So gulp.src( [ files ], { "base" : "." }) can be used in the structure above to copy all the directories recursively.

If, like me, you may forget this then try:

gulp.copy=function(src,dest){
    return gulp.src(src, {base:"."})
        .pipe(gulp.dest(dest));
};
Seth
  • 9,056
  • 9
  • 40
  • 67
M1ke
  • 5,739
  • 4
  • 24
  • 48
60

So - the solution of providing a base works given that all of the paths have the same base path. But if you want to provide different base paths, this still won't work.

One way I solved this problem was by making the beginning of the path relative. For your case:

gulp.src([
    'index.php',
    '*css/**/*',
    '*js/**/*',
    '*src/**/*',
])
.pipe(gulp.dest('/var/www/'));

The reason this works is that Gulp sets the base to be the end of the first explicit chunk - the leading * causes it to set the base at the cwd (which is the result that we all want!)

This only works if you can ensure your folder structure won't have certain paths that could match twice. For example, if you had randomjs/ at the same level as js, you would end up matching both.

This is the only way that I have found to include these as part of a top-level gulp.src function. It would likely be simple to create a plugin/function that could separate out each of those globs so you could specify the base directory for them, however.

ty1824
  • 1,170
  • 9
  • 11
  • I think that having to start with multiple base paths probably goes beyond the scope of the question. From my original question I was moving the files to an absolute path, but the problem still occurred, that without specifying a base, all files from all my globs were copied into a single directory without their existing hierarchy being followed. – M1ke Oct 01 '15 at 08:02
  • 2
    @M1ke It is true, the main point of your question wasn't directed at varying base paths. However, you mentioned `However it flattens the dir structure - all directories are copied but every file is placed in the root /var/www`, and this is actually how I found your question - I was searching for a solution of how to copy recursively with different base paths. Essentially, this solution works for your case without having to specify a default base, but also for a multi-base path case, as long as you can ensure that the leading star matches nothing :) – ty1824 Oct 01 '15 at 08:52
  • 6
    This answer is exceptional. It deals specifically with copying a path from an arbitrary start point, eg. src could be `'assets/subdir/*fonts/*'` to copy the fonts dir. – Wtower Feb 24 '16 at 16:18
-4

If you want to copy the entire contents of a folder recursively into another folder, you can execute the following windows command from gulp:

xcopy /path/to/srcfolder /path/to/destfolder /s /e /y

The /y option at the end is to suppress the overwrite confirmation message.

In Linux, you can execute the following command from gulp:

cp -R /path/to/srcfolder /path/to/destfolder

you can use gulp-exec or gulp-run plugin to execute system commands from gulp.

Related Links:

  1. xcopy usage

  2. gulp-exec and gulp-run

Community
  • 1
  • 1
Manoj Amalraj
  • 453
  • 1
  • 4
  • 13
  • 7
    The issue with falling back to shell here is that you'd lose the ability to run other commands on the stream, such as compression or analytics tools. – M1ke Sep 25 '15 at 10:15