I'm trying to make a program that needs to check if a folder exists. If it does - it deletes and creates it again (to clear it). If it doesn't - it creates it. After that I copy all paths that get returned from a function into that cleared folder. I'm currently running into errors for permssions to delete the folder and also errors for copying the file. I tried chmodSync but I couldn't work it out. Here's my code:
function sortTracks(dir) {
fs.chmodSync(
path.join(dir, "playlist"),
fs.constants.S_IRUSR | fs.constants.S_IWUSR
);
if (fs.existsSync(path.join(dir, "playlist")))
fs.rmdirSync(path.join(dir, "playlist"));
fs.mkdirSync(path.join(dir, "playlist"));
fs.chmodSync(
path.join(dir, "playlist"),
fs.constants.S_IRUSR | fs.constants.S_IWUSR
);
getAllFiles(dir, []).forEach(track => {
fs.chmodSync(track, fs.constants.S_IRUSR);
fs.copyFileSync(track, path.join(dir, "playlist"));
});
}
From what I could tell, sortTracks attempts to:
Set the permissions of ${cwd}/playlist to be readable and writeable by the user
Remove ${dir}/playlist if it already exists
Create the ${dir}/playlist directory
Set the permissions of ${dir}/playlist, as done in step #2
For each file returned by getAllFiles(dir, []):
Set its permissions to be readable by the user
Copy it to ${dir}/playlist
A few things that stood out to me:
Step #1 is redundant. You can see it for yourself - try running the following in bash:
$ mkdir a
$ chmod -rw a
$ rm -rf a
You'll see that a gets created and removed.
Step #4 is redundant. The default permissions for a directory make it readable & writeable.
Removing the directory should be done using:
fs.rmSync(path.join(dir, "playlist"), {recursive: true, force: true});
Instead of fs.rmdirSync (see the docs).
I hope fixing these will resolve the issue for you.
Related
I am coding a website with Next.js and I tried to add google Tag Manager.
I followed the tutorial on the Next.js Github example but for some reasons I can't access to my environment variables.
It says my variable is undefined.
I created a file .env.local on my project folder (at the same level as components, node_modules, pages, etc)
In this file I created a variable like this (test purpose) :
NEXT_PUBLIC_DB_HOST=localhost
And on my index page I tried this code :
console.log("test ", process.env.NEXT_PUBLIC_DB_HOST);
But in my console I get a "test undefined".
I tried to put my variable into an .env file instead, without success.
What I am doing wrong ?
This envs just works in Server Side. To access this envs in Client Side, you need declare in the next.config.js
This way:
module.exports = {
reactStrictMode: true,
env: {
BASE_URL: process.env.BASE_URL,
}
}
Create .env (all environments), .env.development (development environment), and .env.production (production environment).
Add the prefix NEXT_PUBLIC to all of your environment variables.
NEXT_PUBLIC_API_URL=http://localhost:3000/
Use with prefix process.env
process.env.NEXT_PUBLIC_API_URL
Stop the server and restart it:
npm run dev
I hope it works.
This solution for latest version of nextJs (above 9)
Restarting the server worked for me.
Edit & save .env.local
Stop the server and restart it, npm run dev
You should get an output on the next line like this:
> klout#0.1.0 dev
> next dev
Loaded env from [path]/.env.local
For those using NextJS +9 and looking for environment variables in the browser, you should use the NEXT_PUBLIC_ prefix. Example:
NEXT_PUBLIC_ANALYTICS_ID=123456789
See documentation for reference.
After spending countless hours on this, I found that there is a tiny little paragraph in both the pre and post nextjs 9.4 documentation:
(Pre-9.4) https://nextjs.org/docs/api-reference/next.config.js/environment-variables (same as this answer)
Next.js will replace process.env.customKey with 'my-value' at build time.
(^9.4) https://nextjs.org/docs/basic-features/environment-variables
In order to keep server-only secrets safe, Next.js replaces process.env.* with the correct values at build time.
Key words being BUILD TIME. This means you must have set these variables when running next build and not (just) at next start to be available for the client side to access these variables.
This is my next.config.js file.
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
env: {
BASE_URL: process.env.NEXT_PUBLIC_SITE_URL,
},
};
module.exports = nextConfig;
Restart the server and it worked fine. using Nextjs 12.1.0 with typescript
In my case, Im pasting REACT_APP_API_URL instead of NEXT_PUBLIC_API_URL.
Adding with the most recent version of the documentation on this, v12+.
Using the next.config.js file you can specify server and client variables:
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
You can still use an env.local file, and pass the variable in to the next.config.js file. For example:
publicRuntimeConfig: {
DB_URL: process.env.DB_URL
}
And then you can access the variable like this:
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
publicRuntimeConfig.DB_URL;
I'm trying to mutate the value of my config in memory for testing, I've tried adding process.env.ALLOW_CONFIG_MUTATIONS=true in several spots in the application, as well as through the command line and my .env file.
The config.util.getEnv('ALLOW_CONFIG_MUTATION') method always returns undefined.
I've also tried using importFresh and MockRequest as per examples I've seen online, neither of which allow me to mutate the config in memory, and then reset the value later.
Does anyone have any idea about this?
Update: here's an example of what I'm trying to accomplish
const config = require (config);
const app = new App(config)
it(`does a thing with base config`, () => { ... }
it('does a thing with modified config, () => {
// here i would need to modify my config value and
// have it change the original config that's currently in
// application memory
config = newConfig
expect(config.get('newValues')).to.equal(true)
}
Thanks!
If it is the same config module that I have used (I think I is) then add a custom-environment-variables.js OR test.js with you test config.
test.js will need an ENV=test to work and the custom-environment-variables need something like (for Mac's and NPM) $ npm run funcTest -> yarn serverRunning && NODE_ENV=test wdio wdio.conf.js.
the JSON will look something like
{
test: 'Value'
}
I'm in the process of building an npm package which will be installed globally. Is it possible to have non-code files installed alongside code files that can be referenced from code files?
For example, if my package includes someTextFile.txt and a module.js file (and my package.json includes "bin": {"someCommand":"./module.js"}) can I read the contents of someTextFile.txt into memory in module.js? How would I do that?
The following is an example of a module that loads the contents of a file (string) into the global scope.
core.js : the main module file (entry point of package.json)
//:Understanding: module.exports
module.exports = {
reload:(cb)=>{ console.log("[>] Magick reloading to memory"); ReadSpellBook(cb)}
}
//:Understanding: global object
//the following function is only accesible by the magick module
const ReadSpellBook=(cb)=>{
require('fs').readFile(__dirname+"/spellBook.txt","utf8",(e,theSpells)=>{
if(e){ console.log("[!] The Spell Book is MISSING!\n"); cb(e)}
else{
console.log("[*] Reading Spell Book")
//since we want to make the contents of .txt accesible :
global.SpellBook = theSpells // global.SpellBook is now shared accross all the code (global scope)
cb()//callBack
}
})
}
//·: Initialize :.
console.log("[+] Time for some Magick!")
ReadSpellBook((e)=>e?console.log(e):console.log(SpellBook))
spellBook.txt
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ
ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ
ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ
ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ
ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ
If you require it from another piece of code, you will see how it prints to the console and initializes by itself.
If you want to achieve a manual initalization, simply remove the 3 last lines (·: Initialize :.) and use reload() :
const magick = require("core.js")
magick.reload((error)=>{ if(error){throw error}else{
//now you know the SpellBook is loaded
console.log(SpellBook.length)
})
I have built some CLIs which were distributed privately, so I believe I can illuminate a bit here.
Let's say your global modules are installed at a directory called $PATH. When your package will be installed on any machine, it will essentially be extracted at that directory.
When you'll fire up someCommand from any terminal, the module.js will be invoked which was kept at $PATH. If you initially kept the template file in the same directory as your package, then it will be present at that location which is local to module.js.
Assuming you edit the template as a string and then want to write it locally to where the user wished / pwd, you just have to use process.cwd() to get the path to that directory. This totally depends on how you code it out.
In case you want to explicitly include the files only in the npm package, then use files attribute of package.json.
As to particularly answer "how can my code file in the npm package locate the path to the globally installed npm folder in which it is located in a way that is guaranteed to work across OSes and is future proof?", that is very very different from the template thingy you were trying to achieve. Anyway, what you're simply asking here is the global path of npm modules. As a fail safe option, use the path returned by require.main.filename within your code to keep that as a reference.
When you npm publish, it packages everything in the folder, excluding things noted in .npmignore. (If you don't have an .npmignore file, it'll dig into .gitignore. See https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package) So in short, yes, you can package the text file into your module. Installing the module (locally or globally) will get the text file into place in a way you expect.
How do you find the text file once it's installed? __dirname gives you the path of the current file ... if you ask early enough. See https://nodejs.org/docs/latest/api/globals.html#globals_dirname (If you use __dirname inside a closure, it may be the path of the enclosing function.) For the near-term of "future", this doesn't look like it'll change, and will work as expected in all conditions -- whether the module is installed locally or globally, and whether others depend on the module or it's a direct install.
So let's assume the text file is in the same directory as the currently running script:
var fs = require('fs');
var path = require('path');
var dir = __dirname;
function runIt(cb) {
var fullPath = path.combine(__dirname, 'myfile.txt');
fs.readFile(fullPath, 'utf8' , function (e,content) {
if (e) {
return cb(e);
}
// content now has the contents of the file
cb(content);
}
}
module.exports = runIt;
Sweet!
In my windows server, I found the fs.rename function always return the below error:
error code is Error: EPERM: operation not permitted, rename 'C:\javascript\nodejs\a.txt' -> 'C:\javascript\nodejs\b.txt'
The below are the test code:
var fs = require('fs');
fs.writeFileSync('a.txt',"This is a file")
fs.writeFileSync('b.txt',"This is another file")
fs.rename('a.txt','b.txt',function (err) {
console.log("error code is " + err);
});
var text = fs.readFileSync('b.txt', "utf-8");
console.log(text)
However, in the current folder, I do see the original file "a.txt" as well as the new renamed file "b.txt".
fs.rename is just a wrapper to rename, and according to rename docs:
EPERM or EACCES
The directory containing oldpath has the sticky bit (S_ISVTX)
set and the process's effective user ID is neither the user ID
of the file to be deleted nor that of the directory containing
it, and the process is not privileged (Linux: does not have
the CAP_FOWNER capability); or newpath is an existing file and
the directory containing it has the sticky bit set and the
process's effective user ID is neither the user ID of the file
to be replaced nor that of the directory containing it, and
the process is not privileged (Linux: does not have the
CAP_FOWNER capability); or the filesystem containing pathname
does not support renaming of the type requested.
You probably have no permissions to delete the file or the target file name already exists.
After huge struggle found the solution for me .. 👍
"Create new folders"
mkdir E:\Buildagent\npm
mkdir E:\Buildagent\npm-cache
"move npm prefix and the cache"
robocopy c:\Users\the-build-user\AppData\Roaming\npm E:\Buildagent\npm
robocopy c:\Users\the-build-user\AppData\Roaming\npm-cache E:\Buildagent\npm-cache /E /MOVE
"Update the npm config for prefix and cache"
npm config set prefix E:\Buildagent\npm
npm config set cache E:\Buildagent\npm-cache
https://alastaircrabtree.com/fixing-intermittant-eperm-operation-not-permitted-on-npm-install/
I have image files with read-only attribute set in source folder. I need to copy them to destination folder in most cases several times in gulpfile.js.
I am trying to copy src-to-dest files like this:
gulp.task('copy-images', function () {
gulp.src(path_resource_images + '**/*.jpg')
.pipe(gulp.dest(path_app_images));
});
It works once when the dest folder in empty. But for all next calls I've got an exception that file is read-only in dest folder. How can I remove file attr read-only to make image-copy works every time I call it?
You can use gulp-chmod to handle permissions on your files.
So if you want to set your images readable and writable for everybody, you could go with something like:
var chmod = require('gulp-chmod');
gulp.task('copy-images', function() {
gulp.src(path_resource_images + '**/*.jpg')
.pipe(chmod(666))
.pipe(gulp.dest(path_app_images));
});
By passing options attribute. Set mode value to specify permission for any folders that need to be created as output.
gulp.dest("destination-path-here", {"mode": "0777"})
cheers :-)
rimraf can be used to avoid issues with TFS permissions (by deleting destination files before copying files)
var rimraf = require("rimraf");
gulp.task("images_clean", function (cb) {
rimraf(imagesDest, cb);
});