Using electron-boilerplate to create an .exe for windows. It needs to run a .bat file. Once it's packaged, it doesn't run - electron

Using the electron-boilerplate to create an .exe for windows, it needs to run a .bat file. However, using npm start it works but when it gets packaged with npm run release, it doesn't run the .bat
This is my code for the function
const spawn = require('child_process').spawn;
const bat = spawn('cmd.exe', ['/c', 'Install.bat']);
bat.stdout.on('data', (data) => {
var str = String.fromCharCode.apply(null, data);
addLog(data);
console.info(str);
});
bat.stderr.on('data', (data) => {
var str = String.fromCharCode.apply(null, data);
addLog(data,"error");
console.error(str);
});
bat.on('exit', (code) => {
console.log(`Exit ${code}`);
});
Already checked for child-process

When you run electron via npm start it will typically set the current working directory to the folder for the app (containing your package.json). So it will look for cmd.exe in that folder.
After you build the app and run it, the current working directory might be somewhere else, for example C:\\ (on Windows). You can find the current working directory with process.cwd().
To find the app folder regardless of how the app is running, Electron provides electron.app.getAppPath().
So you can use it like this:
const path = require('path');
const cmdPath = path.join(electron.app.getAppPath(),'cmd.exe');
const bat = spawn(cmdPath, ['/c', 'Install.bat']);

Related

Electron Build Windows Folder Structure

Given an application made in electron. The folder structure would look something like:
App
- assets
-models
- exe files
index.html
main.js
When executing the build following the recommendation of the site by entering the following command:
electron-packager . --overwrite --asar=true --platform=win32 --arch=ia32 --icon=assets/icons/win/icon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="Electron Tutorial App"
The electron v.1.7.9 creates the build correctly, however it inside the release-builds / resources folder the app.asar file, so all the content that was inside my models folder becomes inaccessible. Inside this folder were .exe files that should be run on demand.
The system then looks for the files in the following url: parth_do_projeto / resources / app.asar / assets / models /, that is, it considers that the app.assar is a folder, but after the app.asar build is a file.
Since there were .exe files inside the original folder, the app.asar can not absorb executables.
What would be the way I keep these .exe files? If you build the build without the --asar parameter, the program works correctly, enter, all my project folder / source code is exposed.
My question is what is the best way to generate the build, keeping the code closed and making use of .exe files?
The short answer to your question is to use the unpackDir option for the asar option inside of electron-packager. Here is a sample of what this might look like:
'use strict';
... ...
var packager = require('electron-packager');
var electronPackage = require('electron/package.json');
var pkg = require('./package.json');
// pull the electron version from the package.json file
var electronVersion = electronPackage.version;
... ...
var opts = {
name: pkg.name,
platform: 'win32',
arch: 'ia32', // ia32, x64 or all
dir: './', // source location of app
out: './edist/', // destination location for app os/native binaries
ignore: config.electronignore, // don't include these directories in the electron app build
icon: config.icon,
asar: {unpackDir: config.excludeFromASAR}, // compress project/modules into an asar blob excluding some things.
overwrite: true,
prune: true,
electronVersion: electronVersion , // Tell the packager what version of electron to build with
appCopyright: pkg.copyright, // copyright info
appVersion: pkg.version, // The version of the application we are building
win32metadata: { // Windows Only config data
CompanyName: pkg.authors,
ProductName: pkg.name,
FileDescription: pkg.description,
OriginalFilename: pkg.name + '.exe'
}
};
// Build the electron app
gulp.task('build:electron', function (cb) {
console.log('Launching task to package binaries for ' + opts.name + ' v' + opts['appVersion']);
packager(opts, function (err, appPath) {
console.log(' <- packagerDone() ' + err + ' ' + appPath);
console.log(' all done!');
cb();
});
});

Cordova copy www folder to existing build

If we have only changed assets in the www/ folder of our cordova project, and have not altered any of the native code/plugins, shouldn't it be possible to have a script that just replaces the new www/ folder with the existing one in the ios build output?
That way we don't have to re-build the entire ios project using cordova build ios every time we want to make a small change and re-run in the simulator. This would save us a nice chunk of time daily.
Does anything like this exist already?
You have three ways to archive this:
Make absolute symlinks for every file or folder from your root-www-folder to your platform-www-folder. BUT don't symlink the whole www-folder and don't symlink the cordova.js file.
In Xcode -> Build Phases you can put copy-shell-scripts in Copy www directory for every file or folder of your www-folder. It should look like:
cp -R /absolute/path/to/your/app/www/index.html /absolute/path/to/your/app/platforms/ios/www/index.html
You can use a hook. Put the following hook in hooks->after_platform_add->create_symlinks.js and in hooks->after_build->create_symlinks.js. Everytime you add a android or ios platform or build the application the hook will run.
You have to make the script executable and maybe you need to install shelljs from npm.
Here is my hook, modify it to your needs:
#!/usr/bin/env node
var what_to_symlink_from_www = [
"assets",
"index.html"
];
// no need to change below
var path = require("path"),
fs = require("fs"),
shell = require("shelljs"),
rootdir = process.argv[2],
added_platform = process.env.CORDOVA_PLATFORMS,
www = rootdir + "/www/",
android_www = rootdir + "/platforms/android/assets/www/",
ios_www = rootdir + "/platforms/ios/www/",
buildnumber_file = rootdir + "/buildnumber",
buildnumber,
active_platform_www;
shell.echo("\r\nHook start: Symlinking");
if (added_platform === "ios") {
active_platform_www = ios_www;
do_job()
}
else if (added_platform === "android") {
active_platform_www = android_www;
do_job()
}
function do_job() {
what_to_symlink_from_www.forEach(function (item) {
shell.rm("-rf", active_platform_www + item);
shell.ln("-s", www + item, active_platform_www + item);
shell.echo("symlinked: " + item + " to " + active_platform_www);
});
shell.echo("Hook end: Symlinking" + "\r\n");
}
You can just run
cordova prepare
https://cordova.apache.org/docs/en/latest/reference/cordova-cli/#www

Invoking shell scripts on Windows under MSYS using Command

I am trying to invoke commands in Rust (1.0 beta 3) on Windows 7 in an MSYS2 environment, but I cannot understand how to do it.
Suppose that you have this very simple script called myls in your home folder:
#!/bin/bash
ls
And now create a simple program in Rust that calls the script:
use std::process::Command;
use std::path::Path;
fn main()
{
let path_linux_style = Path::new("~/myls").to_str().unwrap();
let path_win_style = Path::new("C:\\msys64\\home\\yourname\\myls").to_str().unwrap();
let out_linux = Command::new(path_linux_style).output();
let out_win = Command::new(path_win_style).output();
match out_linux
{
Ok(_) => println!("Linux path is working!"),
Err(e) => println!("Linux path is not working: {}", e)
}
match out_win
{
Ok(_) => println!("Win path is working!"),
Err(e) => println!("Win path is not working: {}", e)
}
}
Now, if you try to execute it, you will get the following output:
Linux path is not working: The system cannot find the file specified.
(os error 2)
Win path is not working: %1 is not a valid Win32 application.
(os error 193)
So I am not able to invoke any command in MSYS environment.
How can I solve it?
EDIT:
I noticed that if I invoke an executable, the problem doesn't happen, so it seems to be related to invocation of bash script. Anyway, it's quite annoying since it makes compiling projects depending on external C/C++ code (that need to launch configure script) tricky to get to work.
The Windows example doesn't work because Windows isn't a Unix. On Unix-like systems, the #! at the beginning of a script is recognized, and it invokes the executable at the given path as the interpreter. Windows doesn't have this behavior; and even if it did, it wouldn't recognize the path name to the /bin/bash, as that path name is one that msys2 emulates, it is not a native path name.
Instead, you can explicitly execute the script you want using the msys2 shell, by doing something like the following (alter the path as appropriate, I have msys32 installed since it's a 32 bit VM)
let out_win = Command::new("C:\\msys32\\usr\\bin\\sh.exe")
.arg("-c")
.arg(path_win_style)
.output();

Laravel Elixir - Execute cmd on watch update

I'm trying to create an easy workflow for package development and was hoping someone could pint me in the right direction. In short, once a css file has been updated I want to be able to run a command (php artisan vendor:publish --force) to automatically publish the files.
Can this be done with Elixir and if so could anyone point me in the right direction?
regards
This was incredibly useful to get me on the right track, but I found a slightly simpler solution that I thought I would share:
var elixir = require('laravel-elixir');
var gulp = require("gulp");
var shell = require("gulp-shell");
elixir(function(mix) {
mix.task('publish_assets', ['resources/assets/**/*.scss', 'resources/assets/**/*.js']);
});
gulp.task('publish_assets', shell.task([
"php ../../../../artisan vendor:publish --tag=public --force"
]));
It watches all of the js and sass files for changes and runs the publish assets task. Mine is set to only publish the "public" tagged files, and a quick note as well, you will need to install the gulp-shell utility (https://www.npmjs.com/package/gulp-shell) for either of these.
if anyone is looking, this works nicely:
var gulp = require("gulp");
var shell = require("gulp-shell");
var elixir = require("laravel-elixir");
elixir.extend("publish", function() {
var baseDir = this.assetsDir;
gulp.task("publish_assets", function() {
gulp.src("").pipe( shell( [
"php ../../../artisan vendor:publish --force",
"cd ../../../ ; gulp"
]));
});
this.registerWatcher("publish_assets", [
baseDir + '**/*.scss',
baseDir + '**/*.js'
]);
return this.queueTask("publish_assets");
});

How to find path to the package directory when the script is running with `pub run` command

I am writing a package that loads additional data from the lib directory and would like to provide an easy way to load this data with something like this:
const dataPath = 'mypackage/data/data.json';
initializeMyLibrary(dataPath).then((_) {
// library is ready
});
I've made two separate libraries browser.dart and standalone.dart, similar to how it is done in the Intl package.
It is quite easy to load this data from the "browser" environment, but when it comes to the "standalone" environment, it is not so easy, because of the pub run command.
When the script is running with simple $ dart myscript.dart, I can find a package path using dart:io.Platform Platform.script and Platform.packageRoot properties.
But when the script is running with $ pub run tool/mytool, the correct way to load data should be:
detect that the script is running from the pub run command
find the pub server host
load data from this server, because there could be pub transformers and we can't load data directly from the file system.
And even if I want to load data directly from the file system, when the script is running with pub run, Platform.script returns /mytool path.
So, the question is there any way to find that the script is running from pub run and how to find server host for the pub server?
I am not sure that this is the right way, but when I am running script with pub run, Package.script actually returns http://localhost:<port>/myscript.dart. So, when the scheme is http, I can download using http client, and when it is a file, load from the file system.
Something like this:
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as ospath;
Future<List<int>> loadAsBytes(String path) {
final script = Platform.script;
final scheme = Platform.script.scheme;
if (scheme.startsWith('http')) {
return new HttpClient().getUrl(
new Uri(
scheme: script.scheme,
host: script.host,
port: script.port,
path: 'packages/' + path)).then((req) {
return req.close();
}).then((response) {
return response.fold(
new BytesBuilder(),
(b, d) => b..add(d)).then((builder) {
return builder.takeBytes();
});
});
} else if (scheme == 'file') {
return new File(
ospath.join(ospath.dirname(script.path), 'packages', path)).readAsBytes();
}
throw new Exception('...');
}

Resources