1
1
use std:: {
2
- env,
2
+ env, fs , io ,
3
3
ffi:: CString ,
4
4
str:: FromStr ,
5
5
collections:: HashSet ,
6
6
path:: { Path , PathBuf } ,
7
- os:: unix:: process:: CommandExt ,
8
7
process:: { Command , Stdio , exit} ,
9
8
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 }
11
11
} ;
12
12
13
13
use walkdir:: WalkDir ;
@@ -85,9 +85,33 @@ fn add_to_env(var: &str, dir: &str) {
85
85
}
86
86
}
87
87
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
+
88
113
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 ( ) ;
91
115
WalkDir :: new ( & mut * library_path)
92
116
. into_iter ( )
93
117
. filter_map ( |entry| entry. ok ( ) )
@@ -97,9 +121,8 @@ fn gen_library_path(library_path: &mut String, lib_path_file: &String) {
97
121
if let Some ( parent) = entry. path ( ) . parent ( ) {
98
122
if let Some ( parent_str) = parent. to_str ( ) {
99
123
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 ( ) ) ;
103
126
}
104
127
}
105
128
}
@@ -124,16 +147,18 @@ fn print_usage() {
124
147
Use lib4bin for create 'bin' and 'shared' dirs
125
148
126
149
[ Arguments ]:
127
- [EXEC ARGS]... Command line arguments for execution
150
+ [EXEC ARGS]... Command line arguments for execution
128
151
129
152
[ 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
134
157
135
158
[ 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" ,
137
162
env!( "CARGO_PKG_DESCRIPTION" ) ) ;
138
163
}
139
164
@@ -143,12 +168,14 @@ fn main() {
143
168
let mut exec_args: Vec < String > = env:: args ( ) . collect ( ) ;
144
169
145
170
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}/../" ) ;
147
172
if basename ( & sharun_dir) == "bin" &&
148
173
is_file ( & format ! ( "{lower_dir}{SHARUN_NAME}" ) ) {
149
174
sharun_dir = realpath ( & lower_dir)
150
175
}
151
176
177
+ env:: set_var ( "SHARUN_DIR" , & sharun_dir) ;
178
+
152
179
let bin_dir = & format ! ( "{sharun_dir}/bin" ) ;
153
180
let shared_dir = & format ! ( "{sharun_dir}/shared" ) ;
154
181
let shared_bin = & format ! ( "{shared_dir}/bin" ) ;
@@ -201,19 +228,31 @@ fn main() {
201
228
}
202
229
203
230
}
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
+ }
205
244
}
206
245
} 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 ( ) {
209
248
for bin in dir {
210
249
println ! ( "{}" , bin. unwrap( ) . file_name( ) . to_str( ) . unwrap( ) )
211
250
}
212
251
}
213
252
exit ( 1 )
214
253
}
215
254
} else if bin_name == "AppRun" {
216
- let appname_file = & format ! ( "{sharun_dir}/AppName " ) ;
255
+ let appname_file = & format ! ( "{sharun_dir}/.app " ) ;
217
256
let mut appname: String = "" . into ( ) ;
218
257
if !Path :: new ( appname_file) . exists ( ) {
219
258
if let Ok ( dir) = Path :: new ( & sharun_dir) . read_dir ( ) {
@@ -242,19 +281,24 @@ fn main() {
242
281
243
282
if appname. is_empty ( ) {
244
283
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}" ) ;
246
285
exit ( 1 )
247
286
} )
248
287
}
249
288
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
+ }
252
296
let app = & format ! ( "{bin_dir}/{appname}" ) ;
253
297
254
298
if get_env_var ( "ARGV0" ) . is_empty ( ) {
255
299
env:: set_var ( "ARGV0" , arg0)
256
300
}
257
- env:: set_var ( "APPDIR" , sharun_dir) ;
301
+ env:: set_var ( "APPDIR" , & sharun_dir) ;
258
302
259
303
let err = Command :: new ( app)
260
304
. envs ( env:: vars ( ) )
@@ -277,11 +321,22 @@ fn main() {
277
321
library_path = shared_lib
278
322
}
279
323
324
+ read_dotenv ( & sharun_dir) ;
325
+
280
326
let interpreter = get_interpreter ( & library_path) . unwrap_or_else ( |_|{
281
327
eprintln ! ( "Interpreter not found!" ) ;
282
328
exit ( 1 )
283
329
} ) ;
284
330
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
+
285
340
let etc_dir = PathBuf :: from ( format ! ( "{sharun_dir}/etc" ) ) ;
286
341
let share_dir = PathBuf :: from ( format ! ( "{sharun_dir}/share" ) ) ;
287
342
@@ -299,7 +354,8 @@ fn main() {
299
354
for dir in dirs {
300
355
let dir_path = & format ! ( "{library_path}/{dir}" ) ;
301
356
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" )
303
359
}
304
360
if dir. starts_with ( "perl" ) {
305
361
add_to_env ( "PERLLIB" , dir_path)
@@ -318,6 +374,18 @@ fn main() {
318
374
add_to_env ( "QT_PLUGIN_PATH" , plugins)
319
375
}
320
376
}
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
+ }
321
389
if dir. starts_with ( "tcl" ) {
322
390
if Path :: new ( & format ! ( "{dir_path}/msgs" ) ) . exists ( ) {
323
391
add_to_env ( "TCL_LIBRARY" , dir_path) ;
@@ -403,6 +471,12 @@ fn main() {
403
471
add_to_env ( "GSETTINGS_SCHEMA_DIR" , schemas)
404
472
}
405
473
}
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
+ }
406
480
_ => { }
407
481
}
408
482
}
@@ -417,11 +491,20 @@ fn main() {
417
491
if let Ok ( entry) = entry {
418
492
if entry. path ( ) . is_dir ( ) {
419
493
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
+ }
424
506
}
507
+ _ => { }
425
508
}
426
509
}
427
510
}
0 commit comments