How to set up a Kotlin/Native project so that it places resources alongside the executables? - kotlin

My Kotlin/Native project's target is a windows exe file.
I would like to ship a text file (let's call it resource.txt) together with the exe file, the goal being that in the build dir, I would have a directory with the built exe file plus the resource files ( so that all I'd need to do is copy that directory to e.g. C:\Program Files\MySoftware).
On Android, I would place these types of files in the assets dir and they would get bundled in the APK.
Is there something equivalent for Kotlin/Native?
Basically I would like to place the text file alongside Kotlin code ( e.g. in commonMain/resources)
and then I would like to end up with a build output directory that contains the built exe file as well as the text file.
Is there a standardized way to do this? Or do I need to create my own gradle scripts to bundle my exe + other files?

It's tracked to be supported (either Gradle task, or maybe compiler) but not available yet, so a custom Gradle task it has to be
youtrack

As answered by #Dmitri, it's not implemented yet ( see on youtrack , or an issue on github )
I've solved this with a set of gradle tasks:
package: copies the release binary into a new dir package
packageToZip : makes a zip from the package dir, for convenience.
runPackaged : executes the binary in the package dir, where the required resource files are present.
tasks {
val thePackageTask = register("package", Copy::class) {
group = "package"
description = "Copies the release exe and resources into one directory"
from("$buildDir/processedResources/myprojectname/main") {
include("**/*")
}
from("$buildDir/bin/myprojectname/releaseExecutable") {
include("**/*")
}
into("$buildDir/packaged")
includeEmptyDirs = false
dependsOn("myprojectnameProcessResources")
dependsOn("assemble")
}
val zipTask = register<Zip>("packageToZip") {
group = "package"
description = "Copies the release exe and resources into one ZIP file."
archiveFileName.set("packaged.zip")
destinationDirectory.set(file("$buildDir/packagedZip"))
from("$buildDir/packaged")
dependsOn(thePackageTask)
}
named("build").get().dependsOn(zipTask.get())
val runPackaged = register<Exec>("runPackaged") {
group = "package"
description = "Run the exe file in the \"packaged\" directory."
workingDir = File("$buildDir/packaged")
dependsOn(thePackageTask)
}
}
This could probably be improved so that one doesn't have to hardcode the build directory names, and the project names, but this worked for me ;-)

Related

How to access a file within program file without the full path

I am using c++/winrt within a WinUI3 project and I am trying to have the application pull up a text file where users can select an option from it. The file I am trying to reach is in the project folder and included in the project. Currently, I have the file path set to my device so it pulls the text file from my directory. I want the application to be able to read from the program files instead of the long file path that is currently coded. I tried to change the relative path of the file and used the fstream function to read the file. I also tried just using "Aircrafts/Aircrafts.txt" but that did not work either.
Here is a snippet of the code.
fstream aircraftFile;
string info;
void MainWindow::loadPlatformData()
ifstream aircraftFile; //File Object for list
aircraftFile.open("C:\\Users\\TimmyK\\Documents\\GitHub\\sentinel3\\Sentinel3\\Aircrafts\\Aircrafts.txt", ios::in);
My guess is that you are writing a UWP project which is why the full-path access to your file fails. UWP's have restricted access to the file system per Microsoft Docs.
For a UWP project, you mark the file as Content Yes in the file properties so it's placed into your application's layout package. Normally the 'current working directory' is pointing to your packaged program's installed location. You can get a full path to this directory using:
auto installdir = Windows.ApplicationModel::Current().InstalledLocation();
std::wstring str = installdir.Path().c_str();
For Win32 "classic" desktop applications, there's no specific packaging or installation solution so there's lots of different ways to do it. In Visual Studio when you start the debugger or run a program, the "current working directory" is going to be the project directory but if you run the EXE from the command-line, it will be in a different directory.
To find the running EXE's directory per IInspectable, use GetModuleFileName:
wchar_t exePath[MAX_PATH] = {};
DWORD nc = GetModuleFileNameW(nullptr, exePath, MAX_PATH);
if (nc > MAX_PATH || nc == 0)
{
// Error condition
}
A typical pattern is to look in the EXE folder, then 'walk up' the directory to find asset files. This is what we do a lot in DirectX samples for Win32. See FindMedia.

Xcode Build path and copying additional files

I'm writing a plugin for Elgato Stream Deck. https://developer.elgato.com/documentation/stream-deck/sdk/overview/
Basically it is a binary command line tool written in C++/OBJ-C/Swift combined with a JSON manifest and optionally some HTML and JS files as well as different assets (.png, ...). All files have to be included in a folder (com.companyname.pluginname.sdPlugin) which lives in Library/Application Support/com.elgato.StreamDeck/Plugins/
At the moment, I'm building the binary to the default build path (derived data, ...) and manually copy it to the above folder. But I need to build and run that binary with an executable (Stream Deck app) defined in the scheme for debugging under Xcode. The JSON manifest and assets also lives in my xcode project folder and have to be copied manually.
So Before:
After:
So my question: how can I automate that under Xcode? I assume I can do some sort of post build scripting, but I have no knowledge about all that stuff.
Thanks
Solution:
go to target -> build settings
Deployment Location = YES
Installation Build Products Location = / (empty this one!)
Installation Directory = path to folder (= $INSTALL_PATH)
this will copy your binary to the defined installation path
go to target -> build phases
new phase -> run script
cp -r "$SRCROOT"/<FILE OR FOLDER NAME> "$INSTALL_PATH"/<FILE OR FOLDER NAME>
repeat this for all files and folders you need to be copied to the installation path. be careful with empty spaces in the folder/file names, they won't be recognized correctly and you have to use quotation marks

Use Conan package manager to copy files to project

I use Conan to manage the dependencies within my (c++) project.
Now I need some relatively large files in the project, which should not be checked in to GIT. I have these files on a http server and want to download them via a Conan recipe and make them available within my project (the files are needed by the finished binary and have nothing to do with the build process itself).
But I can't get conan to copy the files to the right place, here is my attempt:
from conan's import ConanFile, tools
class MyPackage(ConanFile):
name = "package"
version = "11.28"
author = "Whatever"
keep_imports = True
exports = "*"
def source(self):
tools.get("http://just/a/file.zip")
def imports(self):
self.copy("*", dst="content")
def package(self):
self.copy("*")
def package_id(self):
self.info.header_only()
For example, if my project is located under C:\dev\project and the files A.dat, B/C.dat are located in the "file.zip", I would like to have them under c:\dev\project\ \A.dat or c:\dev\project\ \B\C.dat
The problem is that when I run the recipe, the files are under <CONAN_HOME>\package\11.28\ (...) \package\A.dat or
<CONAN_HOME>\package\11.28\ (...) \package\B\C.dat (Additionally also under <CONAN_HOME>\package\11.28\ ... \source, but that is not important)
and not under c:\dev\project...
You are calling
conan create .
when you run the recipe I suppose. Actually you can't modify you local folder running conan create, but there is one exception to this rule:
if you define a
set_version(self):
self.version = "11.28"
# do whatever you want in your local folder
# e.g. tools.get("http://just/a/file.zip")
# and unpack your files into A.dat and B/C.dat
inside your recipe. All you do inside this function is executed within your current working directory, so you could download your zipfile here and copy the files in it in their locations.
Additionally, you have to pick these files with the exports_sources attribute if you want them to become part of your final package:
exports_sources = "A.dat","B/C.dat"
This is a hack and should be avoided, however.
Try instead to package your files "A.dat" and "C.dat" in a own package say MyDats/1.0, using the following recipe:
class MyPackage(ConanFile):
name = "MyDats"
version = "1.0"
def source(self):
tools.get("http://just/a/file.zip")
# unpack files into A.dat and C.dat herein..
def package(self):
self.copy("*", dest = "include", keep_path = False)
def package_id(self):
self.info.header_only()
By the way: you don't need to specify exports = "*" normally, the only things that should be exported are files that are necessary to run the recipe itself (not source code or your files A.dat, C.dat).
When you call
conan create .
on this it will package your files and install them locally in your cache.
Then place a conanfile.txt in your folder C:\dev\project\import\ of your local project containing:
[requires]
MyDats/1.0
[imports]
include, A.dat -> ..\
include, C.dat -> ..\B
You can obviously put your conanfile.txt in another location than project\import, the main point is to non have two recipes in the same location.
If these file are needed in your finished binary, you should include them into your package of your project however, which is what you did already inadvertently as far as I understood.

How can I make react-native build copy an asset from node_modules to the apk?

I am building a react-native app which embeds a WebView in order to host some non-native react components. I have a small html file which is the source for the WebView and lives in a sub-folder of android/app/src/main/assets, which I understand is where it needs to be for the build to copy it to the apk, though I think I will need another copy in another location for IOS. So far so good...this much works.
Now, the htm file needs to pull in the regular react components from code in an npm module. It contains a script tag whose src needs to reference a file which is available in a subdirectory of node_modules. I don't know of any url I can put in the src that will reference the file direct from node_modules and get it copied to the apk. The simple solution is to manually copy the file into the same subfolder of android/app/src/main/assets and simply use its name as the src. This also works, though there may be a better way.
Problem: how can I automate copying the file from node_modules to assets?
(Ideally, a solution would also work for IOS, though at this point I'd be glad to have an android-only one.)
I explored rnpm and react-native link. Documentation I can find is very inadequate, but it appears this mechanism can only be used for fonts.
I explored adding a copy command to the start script in package.json, like this:
"scripts": {
"start": "copy/Y node_modules/X/Ybundle.js android/app/src/main/assets/X/Ybundle.js & node node_modules/react-native/local-cli/cli.js start"
},
but the copy did not happen when I ran react-native start-android.
I am wondering whether something could be added to the react-native project's gradle script, but cannot find any documentation on how this is used in the react native build process.
The best solution I've found so far is to add some scripts to package.json:
"scripts": {
"copyAssets": "node -e \"fs.copyFileSync('./node_modules/bloom-player-react/output/bloomPlayerControlBundle.js','./android/app/src/main/assets/bloom-player/bloomPlayerControlBundle.js')\"",
"start-android": "npm run copyAssets && react-native run-android",
...
}
Then when I npm run start-android, first the copy happens, and then the normal android startup.
I answered very same question in here with same answer: https://stackoverflow.com/a/72191579/7376041
For Android, you can run a custom Gradle task that able to will handle copy your assets in build time.
Create a Gradle file in your module's root, like below:
(I presume your module name is react-native-my-awesome-module and your HTML files is under www folder in module's root.)
awesome.gradle:
/**
* Register HTML asset source folder
*/
android.sourceSets.main.assets.srcDirs += file("$buildDir/intermediates/ReactNativeMyAwesomeModule")
/**
* Task to copy HTML files
*/
afterEvaluate {
def targetDir = "../../node_modules/react-native-my-awesome-module/www";
def fileNames = [ "*.html" ];
def htmlCopyTask = tasks.create(
name: "copyReactNativeMyAwesomeModuleAssets",
type: Copy) {
description = "copy react native my awesome module assets."
into "$buildDir/intermediates/ReactNativeMyAwesomeModule/www"
fileNames.each { fileName ->
from(targetDir) {
include(fileName)
}
}
}
android.applicationVariants.all { def variant ->
def targetName = variant.name.capitalize()
def generateAssetsTask = tasks.findByName("generate${targetName}Assets")
generateAssetsTask.dependsOn(htmlCopyTask)
}
}
After installing the module, put the below line in your project's android/app/build.gradle file:
apply from: file("../../node_modules/react-native-my-awesome-module/awesome.gradle");
When you build your app, your assets under www folder will be copied from your module. You can access your resources in your app like below :
<WebView
source={{uri: 'file:///android_asset/www/index.html'}}
/>

How to refer a file from jar file in eclipse plugin

I have created an eclipse plugin and I wanted to deploy during eclipse runtime. I have below package structure.
com.myplugin
|
---resources
|
---server.bat
As part of the plugin job, "server.bat" file should be executed.
I packaged the plugin as .jar file including resouces folder in the binary and placed in to the eclipse "plugins" folder.
Plugin took effect and it does work fine, but I have a problem while executing the "server.bat" file, which is inside the jar that I generated. The error message says:
"Windows cannot find "resources\server.bat" make sure you typed name
correctly and try again"
I tried with relative paths and absolute paths, but it didnt work.
Here is the code doing that work:
URL url = Activator.getDefault().getBundle().getEntry("/resources/server.bat");
String fileURL = FileLocator.toFileURL(url).toString();
String commandLine = "cmd.exe /c start " +fileURL;
Process process= Runtime.getRuntime().exec(commandLine);
I got the "fileURL" output:
file:/D:/Program
Files/IBM/SDP/configuration/org.eclipse.osgi/bundles/2392/1/.cp/resources/server.bat
I am not sure this is correct.
Hope this is clear enough to answer the question.
Alternatively, please suggest some other way, such as creating features to deploy the plugin with folder structure. I haven't tried this option yet.
I have had a similar problem when I export my plugin. I had to refer an exe file stored in my plugin jar file. When the plugin was exported I can not access the zipped file, while it is accessible when I develop the plugin cause eclipse looks for the file in my "development folder".
To solve the problem I created a plugin feature and in the "Included Plug-ins" tab of feature.xml I checked the option
Unpack the plug-in archive after the installation.
for the plugin which contains the exe file.
Using this option you will find your plugin files in a folder under the eclipse plugin folder and you will be able to access them as regular files.
For example
Bundle bundle = <get a bundle of your plugin>;
URL url = FileLocator.find(bundle, new Path(<relative path from plugin root to your file>), null);
try {
url = FileLocator.resolve(url);
} catch (IOException e) {
e.printStackTrace();
return false;
}
Otherwise I think you should decompress your jar.
Hope this help.
EDIT
As I said you can create a feature project(for an example look here) and when you add your plugins, check the option "Unpack the plug-in archive after the installation." Eclipse will do the work for you and you will find your plugin unzipped in the eclipse plugin folder. This solved the problem for me.
Your code seems ok. Note that:
You need to convert your fileURL to file path (i.e. remove "file:/" prefix). This is hugely platform-dependent - try to rely on org.eclipse.core.runtime.IPath and java.io.Path (I don't remember proper code, sorry)
You need to escape the path as it contains space character.
I made it worked using ProcessBuilder. Below is the code snippet..
URL url = Platform.getBundle(Activator.PLUGIN_ID).getEntry("resources/server.bat");
String fileURL = FileLocator.toFileURL(url).toString();
ProcessBuilder pb = new ProcessBuilder("cmd.exe","/c",fileURL);
pb.redirectErrorStream(true);
Process p = pb.start();
p.destroy();
Ofcourse, i extracted the jar and put that directory to plugins folder of eclipse.
Use the second solution of http://www.vogella.com/blog/2010/07/06/reading-resources-from-plugin/
And don't forget to export the files you want to access in the build configuration of your plugin.
I found this worked well with Eclipse RCP 4, This code took the given gif image from a jar file that was in the given plugin
public ImageDescriptor getImgDesc(final String bundleId, final String fullPath)
throws IOException {
final URL url = new URL("platform:/plugin/" + bundleId + "/" + fullPath);
final ImageDescriptor imgDesc = ImageDescriptor.createFromURL(url);
return imgDesc;
}
....
final ImageDescriptor imgDesc = getImgDesc("com.awe.test","images/Applet24.gif");
final Image applet24 = imgDesc.createImage();