mem-fs-editor: How to copy relative symlinks? - node.js

I've got a directory which contains a lot of files and one (or more) symlinkname -> . symlink. I want to copy the contents of the entire directory to a new location. the following code copies everything just fine, though it skips the symlink. Adding globOptions.follow = true only makes it loop indefinitely, which makes sense since it will try to dereference it. How can I just make it copy all the content + symlinks without trying to follow them?
this.fs.copy(
this.destinationPath() + '/**',
this.destinationPath('build/html'),
{
globOptions: {
follow: true // This will make the copy loop infinitely, which makes sense.
}
}
});

After finding out that Yeoman is avoiding bad UX by excluding support for symlinks (see Simon Boudrias' comment), I knew I had to work around this issue. I did the following workaround, please note that this should only be applied if you're unable to avoid symlinks like I am.
var fs = require('fs');
// Find out if there are symlinks
var files = fs.readdirSync(this.destinationPath());
for (var i = 0; i < files.length; i++) {
var path = this.destinationPath(files[i]),
stats = fs.lstatSync(path);
if (stats.isSymbolicLink()) {
// Find the target of the symlink and make an identical link into the new location
var link = fs.readlinkSync(path);
fs.symlinkSync(link, this.destinationPath('build/html/' + files[i]));
}
}

Related

How to delete all files and subdirectories in a directory with Node.js

I am working with node.js and need to empty a folder. I read a lot of deleting files or folders. But I didn't find answers, how to delete all files AND folders in my folder Test, without deleting my folder Test` itself.
I try to find a solution with fs or extra-fs. Happy for some help!
EDIT 1: Hey #Harald, you should use the del library that #ziishaned posted above. Because it's much more clean and scalable. And use my answer to learn how it works under the hood :)
EDIT: 2 (Dec 26 2021): I didn't know that there is a fs method named fs.rm that you can use to accomplish the task with just one line of code.
fs.rm(path_to_delete, { recursive: true }, callback)
// or use the synchronous version
fs.rmSync(path_to_delete, { recursive: true })
The above code is analogous to the linux shell command: rm -r path_to_delete.
We use fs.unlink and fs.rmdir to remove files and empty directories respectively. To check if a path represents a directory we can use fs.stat().
So we've to list all the contents in your test directory and remove them one by one.
By the way, I'll be using the synchronous version of fs methods mentioned above (e.g., fs.readdirSync instead of fs.readdir) to make my code simple. But if you're writing a production application then you should use asynchronous version of all the fs methods. I leave it up to you to read the docs here Node.js v14.18.1 File System documentation.
const fs = require("fs");
const path = require("path");
const DIR_TO_CLEAR = "./trash";
emptyDir(DIR_TO_CLEAR);
function emptyDir(dirPath) {
const dirContents = fs.readdirSync(dirPath); // List dir content
for (const fileOrDirPath of dirContents) {
try {
// Get Full path
const fullPath = path.join(dirPath, fileOrDirPath);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
// It's a sub directory
if (fs.readdirSync(fullPath).length) emptyDir(fullPath);
// If the dir is not empty then remove it's contents too(recursively)
fs.rmdirSync(fullPath);
} else fs.unlinkSync(fullPath); // It's a file
} catch (ex) {
console.error(ex.message);
}
}
}
Feel free to ask me if you don't understand anything in the code above :)
You can use del package to delete files and folder within a directory recursively without deleting the parent directory:
Install the required dependency:
npm install del
Use below code to delete subdirectories or files within Test directory without deleting Test directory itself:
const del = require("del");
del.sync(['Test/**', '!Test']);

Node.js fs.writeFile() not creating new files?

I need to create many .json files for the system i am trying to develop. To do this, i ran a for loop over the file names i needed, then used fs.writeFileSync('filename.json', [data]).
However, when trying to open these later, and when I try to find them in the project folder, I cannot find them anywhere.
I have tried writing in a name that was less complex and should have appeared in the same directory as my script, however that was fruitless as well. To my understanding, even if my file name wasn't what I expected it to be, I should get at least something, somewhere, however I end up with nothing changed.
My current code looks like this:
function addEmptyDeparture(date) {
fs.readFileSync(
__dirname + '/reservations/templates/wkend_dep_template.json',
(err, data) => {
if (err) throw err
fs.writeFileSync(
getDepartureFileName(date),
data
)
}
)
}
function getDepartureFileName(date){
return __dirname + '/reservations/' +
date.getFullYear() +
'/departing/' +
(date.getMonth() + 1).toString().padStart(2, "0") +
date.getDate().toString().padStart(2, "0") +
'.json'
}
Where data is the JSON object returned from fs.readFileSync() and is immediately written into fs.writeFileSync(). I don't think I need to stringify this, since it's already a JSON object, but I may be wrong.
The only reason I think it's not working at all (as opposed to simply not showing up in my project) is that, in a later part of the code, we have this:
fs.readFileSync(
getDepartureFileName(date)
)
.toString()
which is where I get an error for not having a file by that name.
It is also worth noting that date is a valid date object, as I was able to test that part in a fiddle.
Is there something I'm misunderstanding in the effects of fs.writeFile(), or is this not the best way to write .json files for use on a server?
You probably are forgetting to stringify the data:
fs.writeFileSync('x.json', JSON.stringify({id: 1}))
I have tried to create similar case using a demo with writeFileSync() creating different files and adding json data to these ,using a for loop. In my case it works . Each time a new file name is created . Here is my GitHub for the same :-
var fs = require('fs');
// Use readFileSync() method
// Store the result (return value) of this
// method in a variable named readMe
for(let i=0 ; i < 4 ; i++) {
var readMe = JSON.stringify({"data" : i});
fs.writeFileSync('writeMe' + i + '.json', readMe, "utf8");
}
// Store the content and read from
// readMe.txt to a file WriteMe.txt
Let me know if this what you have been trying at your end.

Gulp copying empty directories

In my gulp build I've made a task that runs after all compiling, uglifying and minification has occurred. This task simply copies everything from the src into the dest directory that hasn't been touched/processed by earlier tasks. The little issue I'm having is that this results in empty directories in the dest directory.
Is there a way to tell the gulp.src glob to only include files in the pattern matching (like providing the 'is_file' flag)?
Thanks.
Fixed it by adding a filter to the pipeline:
var es = require('event-stream');
var onlyDirs = function(es) {
return es.map(function(file, cb) {
if (file.stat.isFile()) {
return cb(null, file);
} else {
return cb();
}
});
};
// ...
var s = gulp.src(globs)
.pipe(onlyDirs(es))
.pipe(gulp.dest(folders.dest + '/' + module.folder));
// ...
I know I'm late to the party on this one, but for anyone else stumbling upon this question, there is another way to do this that seems pretty elegant in my eyes. I found it in this question
To exclude the empty folders I added { nodir: true } after the glob pattern.
Your general pattern could be such (using the variables from Nick's answer):
gulp.src(globs, { nodir: true })
.pipe(gulp.dest(folders.dest + '/' + module.folder));
Mine was as follows:
gulp.src(['src/**/*', '!src/scss/**/*.scss', '!src/js/**/*.js'], { nodir: true })
.pipe(gulp.dest('dev/'));
This selects all the files from the src directory that are not scss or js files, and does not copy any empty folders from those two directories either.

NodeJS - Copy and Rename all contents in existing directory recursively

I have a directory with folders and files within. I want to copy the entire directory with all its contents to a different location while renaming all the files to something more meaningful. I want to use nodejs to complete this series of operations. What is an easy way to do it, other than moving it one by one and renaming it one by one?
Thanks.
-- Thanks for the comment! So here is an example directory that I have in mind:
-MyFridge
- MyFood.txt
- MyApple.txt
- MyOrange.txt
- ...
- MyDrinks
- MySoda
- MyDietCoke.txt
- MyMilk.txt
- ...
- MyDesserts
- MyIce
...
I want to replace "My" with "Tom," for instance, and I also would like to rename "My" to Tom in all the text files. I am able to copy the directory to a different location using node-fs-extra, but I am having a hard time with renaming the file names.
Define your own tools
const fs = require('fs');
const path = require('path');
function renameFilesRecursive(dir, from, to) {
fs.readdirSync(dir).forEach(it => {
const itsPath = path.resolve(dir, it);
const itsStat = fs.statSync(itsPath);
if (itsPath.search(from) > -1) {
fs.renameSync(itsPath, itsPath.replace(from, to))
}
if (itsStat.isDirectory()) {
renameFilesRecursive(itsPath.replace(from, to), from, to)
}
})
}
Usage
const dir = path.resolve(__dirname, 'src/app');
renameFilesRecursive(dir, /^My/, 'Tom');
renameFilesRecursive(dir, /\.txt$/, '.class');
fs-jetpack has a pretty nice API to deal with problems like that...
const jetpack = require("fs-jetpack");
// Create two fs-jetpack contexts that point
// to source and destination directories.
const src = jetpack.cwd("path/to/source/folder");
const dst = jetpack.cwd("path/to/destination");
// List all files (recursively) in the source directory.
src.find().forEach(path => {
const content = src.read(path, "buffer");
// Transform the path however you need...
const transformedPath = path.replace("My", "Tom");
// Write the file content under new name in the destination directory.
dst.write(transformedPath, content);
});

AAssetManager_openDir crashing app on start

I'm trying to iterate through all the files contained in the assets folder. To get the working directory I use: AAssetManager_openDir. However simply having this in my code causes a crash on startup - android_main doens't even get a look in. Has anybody had similar problems and/or know how to resolve this?
const char* filename = (const char*)NULL;
const char* dirName = "";
AAssetDir* dir = AAssetManager_openDir(assetManager, dirName);
while((filename = AAssetDir_getNextFileName(dir)) != NULL)
{
//action per file
}
AAssetDir_close(dir);
Well I didn't have any luck getting it to work so I tried a different approach.
I compiled a static library of Minizip and, combined with Zlib, opened the APK file (the path of which found via JNIEnv) and found the filenames nestled within, skipping over entries not contained in the assets folder.
Roundabout way to do it but since AAssetManager_openDir isn't working this seemed like the only option.
Still it would be nice if somebody does find the "correct" solution.
const char* dirName = "";
Is probably what is causing the crash.
Instead try:
while(1)
{
const char* filename = AAssetDir_getNextFileName(dir);
if(!filename)
break;
}

Resources