Skip to content

Commit 2307319

Browse files
committed
Add .env parser
Add SHARUN_DIR env Add gimp dirs parser Add SHARUN_WORKING_DIR env var..
1 parent a65e1b8 commit 2307319

File tree

3 files changed

+123
-36
lines changed

3 files changed

+123
-36
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sharun"
3-
version = "0.1.3"
3+
version = "0.1.4"
44
readme = "README.md"
55
license = "MIT"
66
repository = "https://github.com/VHSgunzo/sharun"
@@ -22,3 +22,4 @@ opt-level = 0
2222
[dependencies]
2323
walkdir = "2.5.0"
2424
userland-execve = "0.2.0"
25+
dotenv = { git = "https://github.com/VHSgunzo/dotenv.git" }

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@ cp ./target/$(uname -m)-unknown-linux-musl/release/sharun .
3434
Use lib4bin for create 'bin' and 'shared' dirs
3535
3636
[ Arguments ]:
37-
[EXEC ARGS]... Command line arguments for execution
37+
[EXEC ARGS]... Command line arguments for execution
3838
3939
[ Options ]:
40-
l, lib4bin [ARGS] Launch the built-in lib4bin
41-
-g, --gen-lib-path Generate library path file
42-
-v, --version Print version
43-
-h, --help Print help
40+
l, lib4bin [ARGS] Launch the built-in lib4bin
41+
-g, --gen-lib-path Generate library path file
42+
-v, --version Print version
43+
-h, --help Print help
4444
4545
[ Environments ]:
46-
SHARUN_LDNAME=ld.so Specifies the name of the interpreter
46+
SHARUN_WORKING_DIR=/path Specifies the path to the working directory
47+
SHARUN_LDNAME=ld.so Specifies the name of the interpreter
48+
SHARUN_DIR Sharun directory
4749
```
4850

4951
## Usage lib4bin:
@@ -84,7 +86,8 @@ cp ./target/$(uname -m)-unknown-linux-musl/release/sharun .
8486
./test/sharun bash --version
8587
```
8688

87-
You can also create a symlink from `sharun` to `AppRun` and write the name of the executable file from the `bin` directory to the `AppName` file for compatibility with [AppImage](https://appimage.org) `AppDir`. If the `AppName` file does not exist, the `.desktop` file will be used.
89+
* You can create a symlink from `sharun` to `AppRun` and write the name of the executable file from the `bin` directory to the `.app` file for compatibility with [AppImage](https://appimage.org) `AppDir`. If the `.app` file does not exist, the `*.desktop` file will be used.
90+
* Additional env var can be specified in the `.env` file (see [dotenv](https://crates.io/crates/dotenv)). Env var can also be deleted using `unset ENV_VAR` in the end of the `.env` file.
8891

8992
# Screenshots:
9093
![tree](img/tree.png)

src/main.rs

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::{
2-
env,
2+
env, fs, io,
33
ffi::CString,
44
str::FromStr,
55
collections::HashSet,
66
path::{Path, PathBuf},
7-
os::unix::process::CommandExt,
87
process::{Command, Stdio, exit},
98
io::{Read, Result, Error, Write},
10-
fs::{File, write, read_to_string}
9+
fs::{File, write, read_to_string},
10+
os::unix::{fs::MetadataExt, process::CommandExt}
1111
};
1212

1313
use walkdir::WalkDir;
@@ -85,9 +85,33 @@ fn add_to_env(var: &str, dir: &str) {
8585
}
8686
}
8787

88+
fn read_dotenv(dotenv_dir: &str) {
89+
let dotenv_path = PathBuf::from(format!("{dotenv_dir}/.env"));
90+
if dotenv_path.exists() {
91+
dotenv::from_path(&dotenv_path).ok();
92+
let data = read_to_string(&dotenv_path).unwrap_or_else(|err|{
93+
eprintln!("Failed to read .env file: {}: {err}", dotenv_path.display());
94+
exit(1)
95+
});
96+
for string in data.trim().split("\n") {
97+
let string = string.trim();
98+
if string.starts_with("unset ") {
99+
for var_name in string.split_whitespace().skip(1) {
100+
env::remove_var(var_name)
101+
}
102+
}
103+
}
104+
}
105+
}
106+
107+
fn is_hard_links(file1: &Path, file2: &Path) -> io::Result<bool> {
108+
let metadata1 = fs::metadata(file1)?;
109+
let metadata2 = fs::metadata(file2)?;
110+
Ok(metadata1.ino() == metadata2.ino())
111+
}
112+
88113
fn gen_library_path(library_path: &mut String, lib_path_file: &String) {
89-
let mut added_dirs = HashSet::new();
90-
let mut new_paths = Vec::new();
114+
let mut new_paths: Vec<String> = Vec::new();
91115
WalkDir::new(&mut *library_path)
92116
.into_iter()
93117
.filter_map(|entry| entry.ok())
@@ -97,9 +121,8 @@ fn gen_library_path(library_path: &mut String, lib_path_file: &String) {
97121
if let Some(parent) = entry.path().parent() {
98122
if let Some(parent_str) = parent.to_str() {
99123
if parent_str != library_path && parent.is_dir() &&
100-
!added_dirs.contains(parent_str) {
101-
added_dirs.insert(parent_str.to_string());
102-
new_paths.push(parent_str.to_string());
124+
!new_paths.contains(&parent_str.into()) {
125+
new_paths.push(parent_str.into());
103126
}
104127
}
105128
}
@@ -124,16 +147,18 @@ fn print_usage() {
124147
Use lib4bin for create 'bin' and 'shared' dirs
125148
126149
[ Arguments ]:
127-
[EXEC ARGS]... Command line arguments for execution
150+
[EXEC ARGS]... Command line arguments for execution
128151
129152
[ Options ]:
130-
l, lib4bin [ARGS] Launch the built-in lib4bin
131-
-g, --gen-lib-path Generate library path file
132-
-v, --version Print version
133-
-h, --help Print help
153+
l, lib4bin [ARGS] Launch the built-in lib4bin
154+
-g, --gen-lib-path Generate library path file
155+
-v, --version Print version
156+
-h, --help Print help
134157
135158
[ Environments ]:
136-
SHARUN_LDNAME=ld.so Specifies the name of the interpreter",
159+
SHARUN_WORKING_DIR=/path Specifies the path to the working directory
160+
SHARUN_LDNAME=ld.so Specifies the name of the interpreter
161+
SHARUN_DIR Sharun directory",
137162
env!("CARGO_PKG_DESCRIPTION"));
138163
}
139164

@@ -143,12 +168,14 @@ fn main() {
143168
let mut exec_args: Vec<String> = env::args().collect();
144169

145170
let mut sharun_dir = sharun.parent().unwrap().to_str().unwrap().to_string();
146-
let lower_dir = format!("{sharun_dir}/../");
171+
let lower_dir = &format!("{sharun_dir}/../");
147172
if basename(&sharun_dir) == "bin" &&
148173
is_file(&format!("{lower_dir}{SHARUN_NAME}")) {
149174
sharun_dir = realpath(&lower_dir)
150175
}
151176

177+
env::set_var("SHARUN_DIR", &sharun_dir);
178+
152179
let bin_dir = &format!("{sharun_dir}/bin");
153180
let shared_dir = &format!("{sharun_dir}/shared");
154181
let shared_bin = &format!("{shared_dir}/bin");
@@ -201,19 +228,31 @@ fn main() {
201228
}
202229

203230
}
204-
_ => { bin_name = exec_args.remove(0) }
231+
_ => {
232+
bin_name = exec_args.remove(0);
233+
let bin_path = PathBuf::from(format!("{bin_dir}/{bin_name}"));
234+
let is_hardlink = is_hard_links(&sharun, &bin_path).unwrap_or(false);
235+
if bin_path.exists() && is_hardlink {
236+
let err = Command::new(&bin_path)
237+
.envs(env::vars())
238+
.args(exec_args)
239+
.exec();
240+
eprintln!("Failed to run: {}: {err}", bin_path.display());
241+
exit(1)
242+
}
243+
}
205244
}
206245
} else {
207-
eprintln!("Specify the executable from the 'shared/bin' dir!");
208-
if let Ok(dir) = Path::new(shared_bin).read_dir() {
246+
eprintln!("Specify the executable from: '{bin_dir}'");
247+
if let Ok(dir) = Path::new(bin_dir).read_dir() {
209248
for bin in dir {
210249
println!("{}", bin.unwrap().file_name().to_str().unwrap())
211250
}
212251
}
213252
exit(1)
214253
}
215254
} else if bin_name == "AppRun" {
216-
let appname_file = &format!("{sharun_dir}/AppName");
255+
let appname_file = &format!("{sharun_dir}/.app");
217256
let mut appname: String = "".into();
218257
if !Path::new(appname_file).exists() {
219258
if let Ok(dir) = Path::new(&sharun_dir).read_dir() {
@@ -242,19 +281,24 @@ fn main() {
242281

243282
if appname.is_empty() {
244283
appname = read_to_string(appname_file).unwrap_or_else(|err|{
245-
eprintln!("Failed to read AppName file: {appname_file}: {err}");
284+
eprintln!("Failed to read .app file: {appname_file}: {err}");
246285
exit(1)
247286
})
248287
}
249288

250-
appname = basename(appname.trim())
251-
.replace("'", "").replace("\"", "");
289+
if let Some(name) = appname.trim().split("\n").nth(0) {
290+
appname = basename(name)
291+
.replace("'", "").replace("\"", "")
292+
} else {
293+
eprintln!("Failed to get app name: {appname_file}");
294+
exit(1)
295+
}
252296
let app = &format!("{bin_dir}/{appname}");
253297

254298
if get_env_var("ARGV0").is_empty() {
255299
env::set_var("ARGV0", arg0)
256300
}
257-
env::set_var("APPDIR", sharun_dir);
301+
env::set_var("APPDIR", &sharun_dir);
258302

259303
let err = Command::new(app)
260304
.envs(env::vars())
@@ -277,11 +321,22 @@ fn main() {
277321
library_path = shared_lib
278322
}
279323

324+
read_dotenv(&sharun_dir);
325+
280326
let interpreter = get_interpreter(&library_path).unwrap_or_else(|_|{
281327
eprintln!("Interpreter not found!");
282328
exit(1)
283329
});
284330

331+
let working_dir = &get_env_var("SHARUN_WORKING_DIR");
332+
if !working_dir.is_empty() {
333+
env::set_current_dir(working_dir).unwrap_or_else(|err|{
334+
eprintln!("Failed to change working directory: {working_dir}: {err}");
335+
exit(1)
336+
});
337+
env::remove_var("SHARUN_WORKING_DIR")
338+
}
339+
285340
let etc_dir = PathBuf::from(format!("{sharun_dir}/etc"));
286341
let share_dir = PathBuf::from(format!("{sharun_dir}/share"));
287342

@@ -299,7 +354,8 @@ fn main() {
299354
for dir in dirs {
300355
let dir_path = &format!("{library_path}/{dir}");
301356
if dir.starts_with("python") {
302-
add_to_env("PYTHONHOME", shared_dir)
357+
add_to_env("PYTHONHOME", shared_dir);
358+
env::set_var("PYTHONDONTWRITEBYTECODE", "1")
303359
}
304360
if dir.starts_with("perl") {
305361
add_to_env("PERLLIB", dir_path)
@@ -318,6 +374,18 @@ fn main() {
318374
add_to_env("QT_PLUGIN_PATH", plugins)
319375
}
320376
}
377+
if dir.starts_with("babl-") {
378+
env::set_var("BABL_PATH", dir_path)
379+
}
380+
if dir.starts_with("gegl-") {
381+
env::set_var("GEGL_PATH", dir_path)
382+
}
383+
if dir == "gimp" {
384+
let plugins = &format!("{dir_path}/2.0");
385+
if Path::new(plugins).exists() {
386+
env::set_var("GIMP2_PLUGINDIR", plugins)
387+
}
388+
}
321389
if dir.starts_with("tcl") {
322390
if Path::new(&format!("{dir_path}/msgs")).exists() {
323391
add_to_env("TCL_LIBRARY", dir_path);
@@ -403,6 +471,12 @@ fn main() {
403471
add_to_env("GSETTINGS_SCHEMA_DIR", schemas)
404472
}
405473
}
474+
"gimp" => {
475+
let gimp = &format!("{share}/gimp/2.0");
476+
if Path::new(gimp).exists() {
477+
env::set_var("GIMP2_DATADIR",gimp)
478+
}
479+
}
406480
_ => {}
407481
}
408482
}
@@ -417,11 +491,20 @@ fn main() {
417491
if let Ok(entry) = entry {
418492
if entry.path().is_dir() {
419493
let name = entry.file_name();
420-
if name == "fonts" {
421-
let fonts_conf =etc_dir.join("fonts/fonts.conf");
422-
if fonts_conf.exists() {
423-
env::set_var("FONTCONFIG_FILE", fonts_conf)
494+
match name.to_str().unwrap() {
495+
"fonts" => {
496+
let fonts_conf =etc_dir.join("fonts/fonts.conf");
497+
if fonts_conf.exists() {
498+
env::set_var("FONTCONFIG_FILE", fonts_conf)
499+
}
500+
}
501+
"gimp" => {
502+
let conf =etc_dir.join("gimp/2.0");
503+
if conf.exists() {
504+
env::set_var("GIMP2_SYSCONFDIR", conf)
505+
}
424506
}
507+
_ => {}
425508
}
426509
}
427510
}

0 commit comments

Comments
 (0)