I create a package with several choices and depending on the choice I run a bash script .sh with execFile from node it works fine locally with the path "./utils/myScript.sh
but when I create the package with npm pack and install globally it cannot find the script files in the utils directory.
on the other hand if I put the path /usr/local/lib/node_modules/choicescript/utils/myScript.sh
it works
how to tell it to use relative path and not absolute path
I have another minor problem when the script this launches I have my log but I do not see the return of the script displayed as if I launched this one directly with ./myScript.sh
const program = require("commander");
const chalk = require("chalk");
const inquirer = require("inquirer");
const { execFile } = require("child_process");
let opts = {
shell: "/bin/bash",
};
function devFunc() {
execFile("./utils/myScrypt.sh", opts, (error, stdout, stderr) => {
log(stdout);
log(stderr);
if (error !== null) {
log(`exec error: ${error}`);
}
});
log(chalk.green.bold("\033[32;5mDATABASE DEV RUN - host: 127.0.0.1 - port: 3306\033[0m - ") + chalk.blue.bold(`CTRL+C pour quitter`));
}
const { dev, preprod, prod } = program.opts();
if (dev) {
devFunc();
} else if (preprod) {
preprodFunc();
} else if (prod) {
prodFunc();
} else {
inquirer
.prompt([
{
type: "rawlist",
name: "Database_gcp",
message: "Database choice",
choices: ["dev", "preprod", "prod", "exit"],
},
])
.then((gcp) => {
if (gcp.Database_gcp === "dev") {
devFunc();
}
if (gcp.Database_gcp === "preprod") {
preprodFunc();
}
if (gcp.Database_gcp === "prod") {
prodFunc();
}
if (gcp.Database_gcp === "exit") {
log(chalk.blue("EXIT"));
}
});
}
Instead of doing a relative import/require - you can use the __dirname constant and use "join" for better compatibility. The __dirname yields the full path directory of the current module.
//...
const { join } = require('path');
//...
execFile(join(__dirname, 'utils', 'myScrypt.sh'), opts, (error, stdout, // ...
Related
I'm trying to deploy a smart contract, but before doing so I'm accessing${basePath}/build/ipfsMetasGeneric/_ipfsMetasResponse.json and picking up the metaData.metadata_uri to assign it to PREREVEAL_TOKEN_URI. It all works well until there (I can see on the terminal the console.log (PREREVEAL_TOKEN_URI)). But the app stop working right after as it catches an error and throws me the message CATCH ERROR: ERROR STATUS: 403.
I'm just quite puzzled since I don't understand why the try code runs all Ok but then throws me that error. I've hit a roadblock, would appreciate any help.
Thank you.
Code follows:
const path = require("path");
const basePath = process.cwd();
const fs = require("fs");
const yesno = require('yesno');
const {
fetchNoRetry,
} = require(`${basePath}/utils/functions/fetchWithRetry.js`);
let {
CHAIN,
GENERIC,
CONTRACT_NAME,
CONTRACT_SYMBOL,
METADATA_UPDATABLE,
ROYALTY_SHARE,
ROYALTY_ADDRESS,
MAX_SUPPLY,
MINT_PRICE,
TOKENS_PER_MINT,
OWNER_ADDRESS,
TREASURY_ADDRESS,
PUBLIC_MINT_START_DATE,
BASE_URI,
PREREVEAL_TOKEN_URI,
PRESALE_MINT_START_DATE,
PRESALE_WHITELISTED_ADDRESSES
} = require(`${basePath}/src/config.js`);
const deployContract = async () => {
const ok = await yesno({
question: `Is all REQUIRED contract information correct in config.js? (y/n):`,
default: null,
});
if(!ok) {
console.log("Exiting...");
process.exit(0);
}
if(GENERIC) {
try {
let jsonFile = fs.readFileSync(`${basePath}/build/ipfsMetasGeneric/_ipfsMetasResponse.json`);
let metaData = JSON.parse(jsonFile);
console.log (metaData);
if(metaData.response === "OK") {
if(!PREREVEAL_TOKEN_URI) {
PREREVEAL_TOKEN_URI = metaData.metadata_uri;
console.log (PREREVEAL_TOKEN_URI);
}
} else {
console.log('There is an issue with the metadata upload. Please check the /build/_ipfsMetasGeneric/_ipfsMetasResponse.json file for more information. Running "npm run upload_metadata" may fix this issue.');
}
} catch (err) {
console.log(`/build/_ipfsMetasGeneric/_ipfsMetasResponse.json file not found. Run "npm run upload_metadata" first.`);
console.log(`Catch: ${err}`);
process.exit(0);
}
} else {
try {
let jsonFile = fs.readFileSync(`${basePath}/build/ipfsMetas/_ipfsMetasResponse.json`);
let metaData = JSON.parse(jsonFile);
if(metaData.response === "OK") {
if(!BASE_URI) {
BASE_URI = metaData.metadata_directory_ipfs_uri;
}
} else {
console.log('There is an issue with the metadata upload. Please check the /build/_ipfsMetas/_ipfsMetasResponse.json file for more information. Running "npm run upload_metadata" may fix this issue.');
}
} catch (err) {
console.log(`/build/_ipfsMetasGeneric/_ipfsMetasResponse.json file not found. Run "npm run upload_metadata" first.`);
process.exit(0);
}
}
if (!fs.existsSync(path.join(`${basePath}/build`, "/contract"))) {
fs.mkdirSync(path.join(`${basePath}/build`, "contract"));
}
try {
const url = `https://api.nftport.xyz/v0/contracts/collections`;
const contract = {
chain: CHAIN.toLowerCase(),
name: CONTRACT_NAME,
symbol: CONTRACT_SYMBOL,
owner_address: OWNER_ADDRESS,
metadata_updatable: METADATA_UPDATABLE,
royalties_share: ROYALTY_SHARE,
royalties_address: ROYALTY_ADDRESS,
max_supply: MAX_SUPPLY,
mint_price: MINT_PRICE,
tokens_per_mint: TOKENS_PER_MINT,
treasury_address: TREASURY_ADDRESS,
public_mint_start_date: PUBLIC_MINT_START_DATE,
presale_mint_start_date: PRESALE_MINT_START_DATE,
base_uri: BASE_URI,
prereveal_token_uri: PREREVEAL_TOKEN_URI,
presale_whitelisted_addresses: PRESALE_WHITELISTED_ADDRESSES
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(contract),
};
const response = await fetchNoRetry(url, options);
fs.writeFileSync(`${basePath}/build/contract/_deployContractResponse.json`, JSON.stringify(response, null, 2));
if(response.response === "OK") {
console.log(`Contract deployment started.`);
} else {
console.log(`Contract deployment failed`);
}
console.log(`Check /build/contract/_deployContractResponse.json for more information. Run "npm run get_contract" to get the contract details.`);
} catch (error) {
console.log(`CATCH: Contract deployment failed`, `ERROR: ${error}`);
}
};
deployContract();
On react app, you can create .env.production and .env.development and enter different key and values like this.
REACT_APP_API_URL= "xyz"
to pick environment variables automatically based on commands used --> npm start or npm run build.
What is the equivalent process in preact?
It is my solution
env.js in the root of project:
import fs from 'fs';
import dotenv from 'dotenv';
function getAppEnvironment() {
const prefix = "PREACT";
return Object.keys(process.env)
.filter((key) => new RegExp(`^${prefix}_`, 'i').test(key))
.reduce((env, key) => {
env[key] = process.env[key];
return env;
}, {});
}
function resolveFile(file) {
const path = fs.realpathSync(process.cwd());
return `${path}/${file}`;
}
function getEnvFiles(production) {
const key = production ? 'production' : 'development';
return [
resolveFile(".env"),
resolveFile(".env.local"),
resolveFile(`.env.${key}`),
resolveFile(`.env.${key}.local`),
].filter(Boolean);
}
export function getEnvironment(production) {
const dotenvFiles = getEnvFiles(production);
dotenvFiles.forEach((dotenvFile) => {
if (fs.existsSync(dotenvFile)) {
dotenv.config({
path: dotenvFile,
override: true
})
}
});
return getAppEnvironment();
}
export default getEnvironment;
then create or modify your preact.config.js:
import getEnvironment from './env';
export default {
plugins: [],
webpack(config, env, helpers) {
config.plugins.push(
new helpers.webpack.DefinePlugin({
'process.env': JSON.stringify(getEnvironment(env.production))
}),
);
},
};
I'm using ncp to copy files as following:
import ncp from "ncp";
import { promisify } from "util";
const ncpPromise = promisify(ncp);
const copyAssets = async (exportFolderName, includeSourceMaps) => {
const assets = glob.sync("**/", { cwd: distPath });
const options = { clobber: true, stopOnErr: true };
if (!includeSourceMaps) {
options.filter = (f) => {
return !f.endsWith(".map");
};
}
return Promise.all(
assets.map((asset) => {
return ncpPromise(
path.join(distPath, asset),
path.join(exportPath, exportFolderName, asset),
options
);
})
);
};
But this sometimes fails with the following error:
"ENOENT: no such file or directory, mkdir '/path/to/folder'"
How can I solve this ?
I guess you are trying to copy all files matching for the given glob, so you need to do:
const assets = glob.sync("**/*.*", { cwd: distPath }); // note the *.*
For example, your current glob in question will result into:
[
'folder1/',
'folder2/',
]
whereas the glob in this answer will result into (This is what you want):
[
'folder1/file1.txt',
'folder1/file2.txt',
'folder2/anotherfile.txt',
]
An Alternative:
Seems like ncp isn't being maintained. So, you can use fs-extra, it can copy file and directory as well:
const glob = require("glob");
const path = require("path");
const fs = require("fs-extra");
const copyAssets = async (exportFolderName, includeSourceMaps) => {
const assets = glob.sync("**/*.*", { cwd: distPath });
const options = { overwrite: true };
if (!includeSourceMaps) {
options.filter = (f) => {
return !f.endsWith(".map");
};
}
return Promise.all(
assets.map((asset) => {
return fs
.copy(
path.join(distPath, asset),
path.join(exportPath, exportFolderName, asset),
options
)
.catch((e) => console.log(e));
})
);
};
NPM qir (yes, it is published by myself) is another choice:
const qir = require('qir');
qir.asyncing.copy('/A/path/to/src', '/B/path/to/dest')
.then(() => { /* OK */ }
.catch(ex => { /* Something wrong */ }
;
Here, /A/path/to/src may be a file or a folder, and /B/path/to is not required to exist already.
There is a synchronous way:
const qir = require('qir');
qir.syncing.copy('/A/path/to/src', '/B/path/to/dest');
And, if both src and dest located in the same directory:
const qir = require('qir');
let q = new qir.AsyncDir('/current/working/dir');
q.copy('A/path/to/src', 'B/path/to/dest')
.then(() => { /* OK */ }
.catch(ex => { /* Something wrong */ }
;
It will copy /current/working/dir/A/path/to/src to /current/working/dir/B/path/to/dest.
I'm working on an electron application that performs a screenshot capture every 3 seconds with the electron api, and writes it to a given target path. I've set up a separate BrowserWindow where the capturing code runs in (see code structure below) a setInterval() "loop", but whenever the capture happens, the app freezes for a moment. I think it is the call to source.thumbnail.toPng() or writeScreenshot() method in the file ScreenCapturer.jshtml.js.
I set up this structure as I though this was the way to go, but apparently this is not. WebWorkers won't help me either as I need node modules such as fs, path and desktopCapturer (from electron).
How would one do this type of task without blocking the main thread every time the interval code (as seen in file ScreenCapturer.jshtml.js) runs (because I thought the renderer processes were separate processes?)
My code as reference
main.js (main process)
// all the imports and other
// will only show the import that matters
import ScreenCapturer from './lib/capture/ScreenCapturer';
app.on('ready', () => {
// Where I spawn my main UI
mainWindow = new BrowserWindow({...});
mainWindow.loadURL(...);
// Other startup stuff
// Hee comes the part where I call function to start capturing
initCapture();
});
function initCapture() {
const sc = new ScreenCapturer();
sc.startTakingScreenshots();
}
ScreenCapturer.js (module used by main process)
'use strict';
/* ******************************************************************** */
/* IMPORTS */
import { app, BrowserWindow, ipcMain } from 'electron';
import url from 'url';
import path from 'path';
/* VARIABLES */
let rendererWindow;
/*/********************************************************************///
/*///*/
/* ******************************************************************** */
/* SCREENCAPTURER */
export default class ScreenCapturer {
constructor() {
rendererWindow = new BrowserWindow({
show: true, width: 400, height: 600,
'node-integration': true,
webPreferences: {
webSecurity: false
}
});
rendererWindow.on('close', () => {
rendererWindow = null;
});
}
startTakingScreenshots(interval) {
rendererWindow.webContents.on('did-finish-load', () => {
rendererWindow.openDevTools();
rendererWindow.webContents.send('capture-screenshot', path.join('e:', 'temp'));
});
rendererWindow.loadURL(
url.format({
pathname: path.join(__dirname, 'ScreenCapturer.jshtml.html'),
protocol: 'file:',
slashes: true
})
);
}
}
/*/********************************************************************///
/*///*/
ScreenCapturer.jshtml.js (the thml file loaded in the renderer browser window)
<html>
<body>
<script>require('./ScreenCapturer.jshtml.js')</script>
</body>
</html>
ScreenCapturer.jshtml.js (the js file loaded from the html file in the renderer process)
import { ipcRenderer, desktopCapturer, screen } from 'electron';
import path from 'path';
import fs from 'fs';
import moment from 'moment';
let mainSource;
function getMainSource(mainSource, desktopCapturer, screen, done) {
if(mainSource === undefined) {
const options = {
types: ['screen'],
thumbnailSize: screen.getPrimaryDisplay().workAreaSize
};
desktopCapturer.getSources(options, (err, sources) => {
if (err) return console.log('Cannot capture screen:', err);
const isMainSource = source => source.name === 'Entire screen' || source.name === 'Screen 1';
done(sources.filter(isMainSource)[0]);
});
} else {
done(mainSource);
}
}
function writeScreenshot(png, filePath) {
fs.writeFile(filePath, png, err => {
if (err) { console.log('Cannot write file:', err); }
return;
});
}
ipcRenderer.on('capture-screenshot', (evt, targetPath) => {
setInterval(() => {
getMainSource(mainSource, desktopCapturer, screen, source => {
const png = source.thumbnail.toPng();
const filePath = path.join(targetPath, `${moment().format('yyyyMMdd_HHmmss')}.png`);
writeScreenshot(png, filePath);
});
}, 3000);
});
I walked away from using the API's delivered by electron. I'd recommend using desktop-screenshot package -> https://www.npmjs.com/package/desktop-screenshot. This worked cross platform (linux, mac, win) for me.
Note on windows we need the hazardous package, because otherwise when packaging your electron app with an asar it won't be able to execute the script inside desktop-screenshot. More info on the hazardous package's page.
Below is how my code now roughly works, please don't copy/paste because it might not fit your solution!! However it might give an indication on how you could solve it.
/* ******************************************************************** */
/* MODULE IMPORTS */
import { remote, nativeImage } from 'electron';
import path from 'path';
import os from 'os';
import { exec } from 'child_process';
import moment from 'moment';
import screenshot from 'desktop-screenshot';
/* */
/*/********************************************************************///
/* ******************************************************************** */
/* CLASS */
export default class ScreenshotTaker {
constructor() {
this.name = "ScreenshotTaker";
}
start(cb) {
const fileName = `cap_${moment().format('YYYYMMDD_HHmmss')}.png`;
const destFolder = global.config.app('capture.screenshots');
const outputPath = path.join(destFolder, fileName);
const platform = os.platform();
if(platform === 'win32') {
this.performWindowsCapture(cb, outputPath);
}
if(platform === 'darwin') {
this.performMacOSCapture(cb, outputPath);
}
if(platform === 'linux') {
this.performLinuxCapture(cb, outputPath);
}
}
performLinuxCapture(cb, outputPath) {
// debian
exec(`import -window root "${outputPath}"`, (error, stdout, stderr) => {
if(error) {
cb(error, null, outputPath);
} else {
cb(null, stdout, outputPath);
}
});
}
performMacOSCapture(cb, outputPath) {
this.performWindowsCapture(cb, outputPath);
}
performWindowsCapture(cb, outputPath) {
require('hazardous');
screenshot(outputPath, (err, complete) => {
if(err) {
cb(err, null, outputPath);
} else {
cb(null, complete, outputPath);
}
});
}
}
/*/********************************************************************///
I'm trying to implement a few e2e tests in my aurelia-cli app. I've tried looking for docs or blogs but haven't found anything on e2e setup for the cli. I've made the following adjustments to the project.
first I added this to aurelia.json
"e2eTestRunner": {
"id": "protractor",
"displayName": "Protractor",
"source": "test/e2e/src/**/*.ts",
"dist": "test/e2e/dist/",
"typingsSource": [
"typings/**/*.d.ts",
"custom_typings/**/*.d.ts"
]
},
Also added the e2e tasks on aurelia_project/tasks:
e2e.ts
import * as project from '../aurelia.json';
import * as gulp from 'gulp';
import * as del from 'del';
import * as typescript from 'gulp-typescript';
import * as tsConfig from '../../tsconfig.json';
import {CLIOptions} from 'aurelia-cli';
import { webdriver_update, protractor } from 'gulp-protractor';
function clean() {
return del(project.e2eTestRunner.dist + '*');
}
function build() {
var typescriptCompiler = typescriptCompiler || null;
if ( !typescriptCompiler ) {
delete tsConfig.compilerOptions.lib;
typescriptCompiler = typescript.createProject(Object.assign({}, tsConfig.compilerOptions, {
// Add any special overrides for the compiler here
module: 'commonjs'
}));
}
return gulp.src(project.e2eTestRunner.typingsSource.concat(project.e2eTestRunner.source))
.pipe(typescript(typescriptCompiler))
.pipe(gulp.dest(project.e2eTestRunner.dist));
}
// runs build-e2e task
// then runs end to end tasks
// using Protractor: http://angular.github.io/protractor/
function e2e() {
return gulp.src(project.e2eTestRunner.dist + '**/*.js')
.pipe(protractor({
configFile: 'protractor.conf.js',
args: ['--baseUrl', 'http://127.0.0.1:9000']
}))
.on('end', function() { process.exit(); })
.on('error', function(e) { throw e; });
}
export default gulp.series(
webdriver_update,
clean,
build,
e2e
);
and the e2e.json
{
"name": "e2e",
"description": "Runs all e2e tests and reports the results.",
"flags": []
}
I've added a protractor.conf file and aurelia.protractor to the root of my project
protractor.conf.js
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
//seleniumAddress: 'http://0.0.0.0:4444',
specs: ['test/e2e/dist/*.js'],
plugins: [{
path: 'aurelia.protractor.js'
}],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
aurelia.protractor.js
/* Aurelia Protractor Plugin */
function addValueBindLocator() {
by.addLocator('valueBind', function (bindingModel, opt_parentElement) {
var using = opt_parentElement || document;
var matches = using.querySelectorAll('*[value\\.bind="' + bindingModel +'"]');
var result;
if (matches.length === 0) {
result = null;
} else if (matches.length === 1) {
result = matches[0];
} else {
result = matches;
}
return result;
});
}
function loadAndWaitForAureliaPage(pageUrl) {
browser.get(pageUrl);
return browser.executeAsyncScript(
'var cb = arguments[arguments.length - 1];' +
'document.addEventListener("aurelia-composed", function (e) {' +
' cb("Aurelia App composed")' +
'}, false);'
).then(function(result){
console.log(result);
return result;
});
}
function waitForRouterComplete() {
return browser.executeAsyncScript(
'var cb = arguments[arguments.length - 1];' +
'document.querySelector("[aurelia-app]")' +
'.aurelia.subscribeOnce("router:navigation:complete", function() {' +
' cb(true)' +
'});'
).then(function(result){
return result;
});
}
/* Plugin hooks */
exports.setup = function(config) {
// Ignore the default Angular synchronization helpers
browser.ignoreSynchronization = true;
// add the aurelia specific valueBind locator
addValueBindLocator();
// attach a new way to browser.get a page and wait for Aurelia to complete loading
browser.loadAndWaitForAureliaPage = loadAndWaitForAureliaPage;
// wait for router navigations to complete
browser.waitForRouterComplete = waitForRouterComplete;
};
exports.teardown = function(config) {};
exports.postResults = function(config) {};
and I added a sample test in my test/e2e/src folder it doesn't get executed. I've also tried implementing a e2e test within the unit test folder since when I run au test I see that a chrome browser opens up.
describe('aurelia homepage', function() {
it('should load page', function() {
browser.get('http://www.aurelia.io');
expect(browser.getTitle()).toEqual('Home | Aurelia');
});
});
But this throws the error browser is undefined. Am I missing something with e2e testing with the cli? I know aurelia-protractor comes pre-installed but I don't see any way to run it.
I know this is a very late answer, but perhaps for others looking for an answer, you could try to import from the aurelia-protractor plugin
import {browser} from 'aurelia-protractor-plugin/protractor';