How to copy a file to every directory with Grunt? - gruntjs

So I'm building a WP plugin and it's customary to put empty index.html files into every folder to prevent directory listing where the host allows it. I'm building the deployment-ready package with grunt, but the only thing I'm missing are these files. I have many folders and would rather not create these files by hand. I'm happy to create one, and make Grunt copy that file to every path. But how?

No additional grunt plug-ins are necessary. Your requirement can be achieved using Grunt's built-in features.
Consider adding a custom Task to your Gruntfile.js as per the one named createEmptyHtmlFiles shown below.
Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
// ...
});
/**
* Custom task to create empty `index.html` file in all folders.
*/
grunt.registerTask('createEmptyHtmlFiles', function() {
var fileName = 'index.html',
contents = '';
grunt.file.expand({ filter: 'isDirectory' }, 'dist/**/*')
.forEach(function(dirPath) {
var htmlFilePath = dirPath + '/' + fileName;
grunt.file.write(htmlFilePath, contents, { encoding: 'utf8'})
});
});
grunt.registerTask('default', ['createEmptyHtmlFiles']);
};
Explanation:
Typically your Gruntfile.js will include grunt.initConfig({ ... }); section that defines the configuration of various Tasks that you want to perform. This part should remain as per your current configuration.
A custom Task named createEmptyHtmlFiles is registered that does the following:
Assigns the desired filename, i.e. index.html, to the fileName variable and also assigns an empty string to the contents variable.
Next we utilize grunt.file.expand to which we pass a globbing pattern. In the example above the glob provided is 'dist/**/*'. The globbing pattern combined with the filter: 'isDirectory' option essentially obtains the pathnames to all folders inside the dist directory.
Important: This glob pattern you will need to change as per your directory structure.
Next we iterate each directory pathname using the Array's forEach method.
In each turn of the forEach loop we assign to the htmlFilePath variable a new pathname for where the resultant index.html file is to be created.
Each index.html file is created using grunt.file.write.
Demo:
Lets say the project directory is structured as follows:
.
├── Gruntfile.js
├── dist
│   ├── a
│   │   ├── b
│   │   │   └── 1.txt
│   │   └── c
│   │   └── 2.txt
│   ├── d
│   │   ├── 3.txt
│   │   └── e
│   │   └── 4.txt
│   └── f
│   └── g
│   └── 5.txt
├── node_modules
│ └── ...
└── package.json
Given the Gruntfile.js above after running $ grunt it will change to the following:
.
├── Gruntfile.js
├── dist
│   ├── a
│   │   ├── b
│   │   │   ├── 1.txt
│   │   │   └── index.html <-----
│   │   ├── c
│   │   │   ├── 2.txt
│   │   │   └── index.html <-----
│   │   └── index.html <-----
│   ├── d
│   │   ├── 3.txt
│   │   ├── e
│   │   │   ├── 4.txt
│   │   │   └── index.html <-----
│   │   └── index.html <-----
│   └── f
│   ├── g
│   │   ├── 5.txt
│   │   └── index.html <-----
│   └── index.html <-----
├── node_modules
│ └── ...
└── package.json
Note Every folder inside the dist directory now includes an empty index.html file.
You may need to exclude the index.html from being created in specific directories. In which case we can you can negate specific directories via the glob pattern(s) passed to the grunt.file.expand method.
For instance, lets say we configure it as follows in the createEmptyHtmlFiles task:
...
grunt.file.expand({ filter: 'isDirectory' }, ['dist/**/*', '!dist/a/{b,c}'])
...
Note: This time we pass an Array that contains two glob patterns. The first one is the same as per the previous example, however the second one begins with ! which will negate a match.
Running $ grunt using the the aforementioned glob patterns will result in the following directory structure:
.
├── Gruntfile.js
├── dist
│ ├── a
│ │ ├── b
│ │ │ └── 1.txt
│ │ ├── c
│ │ │ └── 2.txt
│ │ └── index.html <-----
│ ├── d
│ │ ├── 3.txt
│ │ ├── e
│ │ │ ├── 4.txt
│ │ │ └── index.html <-----
│ │ └── index.html <-----
│ └── f
│ ├── g
│ │ ├── 5.txt
│ │ └── index.html <-----
│ └── index.html <-----
├── node_modules
│ └── ...
└── package.json
Note Every folder inside the dist directory, excluding folders b and c, now include an empty index.html file.
btw. When you say "empty index.html files", I've taken that literally. However if you did need some html markup in each file you can assign that to the contents variable. For example:
contents = '<!DOCTYPE html>\n<html>\n<head></head>\n<body></body>\n</html>';
But I said "copy a file ..."
In which case you can change the custom Task to the following:
/**
* Custom task to copy a source `index.html` file in all folders.
*/
grunt.registerTask('copyFileToFolders', function() {
var srcFilePath = './path/to/file/to/copy/index.html';
grunt.file.expand({ filter: 'isDirectory' }, 'dist/**/*')
.forEach(function(dirPath) {
grunt.file.copy(srcFilePath, dirPath + '/index.html')
});
});
Notes:
This utilizes grunt.file.copy to copy the source file to all folders.
The pathname assigned to the srcFilePath variable should be substituted with a real pathname to the actual master index.html file that you want to copy to all folders.
As per the first example, the glob pattern passed to grunt.file.expand must be change as necessary.

Related

How to move files found with pattern and move to another subdirectory in unix

I have this:
.
├── dirA
│   └── ProdA
│   ├── Brief
│   │   └── Form.xlsx
│   ├── Results
│   └── Studies
└── dirB
└── BrandB
└── ProdB
├── Brief
│   └── Form.xlsx
└── Results
and i want this:
.
├── dirA
│   └── ProdA
│   ├── Brief
│   ├── Results
│   └── Studies
│      └── Form.xlsx
└── dirB
└── BrandB
└── ProdB
├── Brief
└── Results
└── Studies
└── Form.xslx
So basically i have to find files Form.xlsx and move it from subdirectory Brief to subdirectory Studies (create it if it does not exists), both at the same level.
when i do:
find . -name '*.xlsx' -exec mv '{}' ../Studies ';'
I got:
.
├── dirA
│   └── ProdA
│   ├── Brief
│   ├── Results
│   └── Studies
└── dirB
└── BrandB
└── ProdB
├── Brief
└── Results
You shouldn't use .. to get the matched file's parent directory, use dirname instead.
find . -name "*.xlsx" -exec sh -c 'mv {} "$(dirname $(dirname {}))/Studies/"' \;
Have a try! :)

rsync include only directory pattern

I want to include only directories named *cache*, and all files and subdirectories under them.
How to write rync --include --exclude?
source dest
├── a │
├── b ├── b
│   └── d │   └── d
│   └── e │   └── e
│   └── cache │   └── cache
├── c ├── c
│   └── f │   └── f
│   └── npm_cache │   └── npm_cache
├── g ├── g
│   └── cache_stores │   └── cache_stores
├── h ├── h
│   └── cache │   └── cache
│   └── i │   └── i
│   └── j │   └── j
└── k │
└── l │
This should work:
--include='*/'
--include='*cache*/**'
--exclude='*'
--prune-empty-dirs
That says:
Include all folders (this is necessary to search inside them).
Include all files with "cache" in the name of a parent directory.
Exclude everything else.
Prune away any folders that were copied but turned out to contain no caches. Unfortunately, this also removes any empty folders within cache directories, but hopefully that's not important to you.
I have accepted ams's answer, but if you don't know rsync --include --exclude syntax (I don't), get an explicit file list with find first.
cd source
find . | grep /.*cache.*/ | rsync --files-from=- source dest

Custom grunt configuration

I'm porting an application from php to node(sailsjs) at the same time trying to replace ant with grunt. I like the current project build structure and I would like to preserve some of it.
It looks like below...
project root
├── build (git ignored)
│   ├── coverage
│   ├── dist(to be deployed to target env)
│   └── local(to be deployed to local env)
├── lib
│   └── some library files like selenium..etc.
├── src
│   ├── conf
│   │   └── target/local properties
│   ├── scripts(may not be needed with grunt??)
│   │   ├── db
│   │   │   └── create_scripts...
│   │   ├── se
│   │   │   └── run_selenium_scripts...
│   │   └── tests
│   │   └── run_unit_test_scripts...
│   ├── tests
│   │   └── test_code....
│   └── webapp(this is where I'd like to place node[sailsjs] code)
│      └── code....
└── wiki .etc...
It doesn't exactly have to be the same way as above but more or less I prefer to build something similar. Now, pretty much all the sailsjs examples I have seen look like below.
project root
├── .tmp
│   └── stuff...
├── package.json
├── tasks
│   ├── config
│   │   └── grunt task configs...
│   └── register
│      └── grunt task registrations...
├── tests
│   ├── unit
│   └── selenium
└── Gruntfile.js
Where should I place Gruntfile.js, app.js, package.json to achieve what I want? What other detail should I have to make grunt function and create artifacts as I want them?
Note: Obviously I'm not expecting to get all the details of grunt configuration. But I guess it helps to see where most important things go and how basic tasks could be configured.
Thanks for your answer.
It's hard to give a precise answer without a detail of your build steps, but I would suggest:
Gruntfile.js and package.json go to your root folder
you setup your individual build tasks (whatever they are) to output to build: see the doc of each task on how to do that, it's usually the dest option
Hope this helps a bit.

Compass and SASS on complex project structure

I'm developing an Angular application and I'm using the following folder structure:
.
├── app
│   ├── assets
│   │   ├── images
│   │   │   ├── brands
│   │   │   ├── coletaSeletiva
│   │   │   ├── quiz
│   │   │   └── vidaEmLem
│   │   │   └── avatars
│   │   ├── sass
│   │   └── stylesheets
│   ├── scripts
│   │   └── controllers
│   └── views
│   └── coleta
└── test
└── spec
└── controllers
This is the yeoman angular generated project.
The generated css that come from SASS is pointing to files with the following path '/app/assets/...', because config in at the project's root.
My server is starting from app folder, so I call my assets using just /assets/...
What should I do?
Should I place config.rb inside of app folder and change assets paths?
My config.rb looks like this:
http_path = "/"
css_dir = "app/assets/stylesheets"
sass_dir = "app/assets/sass"
images_dir = "app/assets/images"
javascripts_dir = "app/assets/javascripts"
relative_assets = true
You can minify your code with "grunt" or "grunt --force". Then i think there will be no issues.
If still you got the issue of images . Try to set the path like ../images/image.png [if image folder is in parent folder] or ./images/image.png [if image folder is in the same folder].

Meteor - correct structure and scope for javascript functions and files?

First of all, I am familiar with what the Meteor docs say about this, which I have summarized here:
Files in subdirectories are loaded before files in parent
directories, so that files in the deepest subdirectory are loaded
first, and files in the root directory are loaded last.
Within a directory, files are loaded in alphabetical order by
filename.
After sorting as described above, all files under directories named
lib are moved before everything else (preserving their order).
Finally, all files that match main.* are moved after everything else
(preserving their order).
(Not sure why they say "moved" instead of "loaded", but I think they just mean "loaded".)
My app has the following structure:
├── client/
│   ├── html/
│   │   ├── main.html
│   │   ├── nav.html
│   │   └── login.html
│   ├── js/
│   │   ├── lib/
│   │   │   └── util.js
│   │   ├── main.js
│   │   └── nav.js
│   └── my_app.less
├── packages/
│   └── some_stuff_here
├── server/
│   └── main.js
├── shared.js
├── smart.json
└── smart.lock
In client/js/nav.js file I have the following JavaScript code:
Template.nav.nav_close = function() {
return ! Session.get(slugify(this.name)+'-nav-close')
}
In client/js/lib/util.js file I have the following JavaScript code:
var slugify = function(value) {
if (value) {
return value.replace(/\s+/g, '-').replace(/\./g, '-').toLowerCase();
}
}
My understanding is that the client/js/lib/util.js file should get loaded first, which will make my slugify function available, and then client/js/nav.js should get loaded and the slugify function should be available to it.
In fact what happens is that I see the following error in my Chrome console:
Exception from Deps recompute function: ReferenceError: slugify is not defined
at Object.Template.nav.nav_close (http://localhost:3000/client/js/nav.js?4d7c7953063828c0e4ec237c1a5c67b849076cb5:2:26)
Why am I getting this error?
slugify has file scope because it is declared with var. Remove var to give it package (application) scope.
Meteor Namespacing
slugify = function(value) {
if (value) {
return value.replace(/\s+/g, '-').replace(/\./g, '-').toLowerCase();
}
}

Resources