source_win_bat 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/source_win_bat.rb +327 -160
- data/source_win_bat.gemspec +1 -1
- data/test/set_diff_case_env.cmd +5 -0
- data/test/test_diffrent_case_envvar_bug.bash +26 -0
- data/test/test_optionparsebug.bash +1 -1
- data/test/test_setdoskey.bash +3 -3
- metadata +3 -2
- data/source_win_bat-0.1.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 124a161b8c1f79c0be6b1e9093929776da276aa2f6877477887153266929a075
|
4
|
+
data.tar.gz: 832bee8c90c33ba7b4cfbc157b7fbbd4b1727cdac4c6f6e3d2f6a099de9040c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8378f7c810a1570633f2f727b4c425f80410e0283b4cdc8cf15ef3ade5f4fa4d9b39c2dd384f72193c704384a459a435805dedea51648e7422b6200064d34be5
|
7
|
+
data.tar.gz: 59325860b1d3fc11828def95aa2735a4cff93142ce96da76c67c380828d4ef023f1929fe8ba73f40d1030351e506831be00007a67429c2f438ca92581c871315
|
data/lib/source_win_bat.rb
CHANGED
@@ -4,64 +4,57 @@ require 'securerandom'
|
|
4
4
|
require 'tmpdir'
|
5
5
|
require_relative 'unixcompatenv'
|
6
6
|
|
7
|
+
class CaseSensitiveVariableError < StandardError
|
8
|
+
end
|
9
|
+
|
7
10
|
class SourceWindowsBatch
|
8
11
|
|
9
|
-
VERSION = "0.
|
12
|
+
VERSION = "0.4.0"
|
13
|
+
|
14
|
+
@args = nil
|
15
|
+
@codepage = nil
|
16
|
+
@file_enc_opts = {}
|
10
17
|
|
11
18
|
def main(argv)
|
12
|
-
|
19
|
+
@args = parse_args!(argv)
|
20
|
+
@args.merge!(parse_option_envs())
|
13
21
|
|
14
22
|
unless [:cygwin, :msys, :wsl].include? UnixCompatEnv.compat_env
|
15
23
|
raise "You're in an unsupported UNIX compatible environment"
|
16
24
|
end
|
17
25
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
cwd_tmp_file_in = mk_tmpname(".cwd")
|
22
|
-
win_cmd = argv[3..-1].map {|v| "#{v}"}.join(" ")
|
23
|
-
win_cmd += " & call set SW_EXITSTATUS=%^ERRORLEVEL% "
|
24
|
-
win_cmd = concat_envdump(win_cmd, env_tmp_file_in)
|
25
|
-
win_cmd = concat_macrodump(win_cmd, macro_tmp_file_in)
|
26
|
-
win_cmd = concat_cwddump(win_cmd, cwd_tmp_file_in)
|
27
|
-
win_cmd += " & call exit %^SW_EXITSTATUS%"
|
28
|
-
if options[:show_cmd]
|
29
|
-
STDERR.puts "SW: " + win_cmd
|
30
|
-
end
|
26
|
+
load_codepage()
|
27
|
+
win_cmd, outfiles, proc_env = make_envsync_cmd(@args[:win_cmd])
|
28
|
+
|
31
29
|
Signal.trap(:INT, "SIG_IGN")
|
30
|
+
|
32
31
|
if UnixCompatEnv.compat_env == :wsl
|
33
32
|
# * Skip winpty, assuming the system's WSL supports ConPTY
|
34
|
-
# * Use an absolute path since
|
35
|
-
pid = Process.spawn(
|
33
|
+
# * Use an absolute path since SWB overwrites PATH with Windows-style PATH in WSL
|
34
|
+
pid = Process.spawn(proc_env,
|
36
35
|
UnixCompatEnv.to_compat_path('C:\\Windows\\System32\\cmd.exe'),
|
37
36
|
'/C', win_cmd, :in => 0, :out => 1, :err => 2)
|
38
37
|
elsif !STDOUT.isatty
|
39
|
-
pid = Process.spawn(
|
38
|
+
pid = Process.spawn(proc_env, 'cmd.exe', '/C', win_cmd, :in => 0, :out => 1, :err => 2)
|
40
39
|
else
|
41
|
-
pid = Process.spawn(
|
40
|
+
pid = Process.spawn(prov_env, 'winpty', '--', 'cmd.exe', '/C', win_cmd, :in => 0, :out => 1, :err => 2)
|
42
41
|
end
|
42
|
+
|
43
43
|
Signal.trap(:INT) do
|
44
44
|
Process.signal("-KILL", pid)
|
45
45
|
end
|
46
|
+
|
46
47
|
status = nil
|
47
48
|
loop do
|
48
49
|
_, status = Process.wait2(pid)
|
49
50
|
break if status.exited?
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
if !options[:preserve_dump]
|
58
|
-
[env_tmp_file_in, macro_tmp_file_in, cwd_tmp_file_in].each do |f|
|
59
|
-
File.delete f
|
60
|
-
end
|
61
|
-
end
|
62
|
-
rescue Errno::ENOENT
|
63
|
-
# ignore
|
64
|
-
end
|
53
|
+
conv_setenv_stmts(outfiles[:env_windump_file], @args[:env_sync_file])
|
54
|
+
conv_doskey_stmts(outfiles[:macro_windump_file], @args[:macro_sync_file])
|
55
|
+
gen_chdir_cmds(outfiles[:cwd_windump_file], @args[:cwd_sync_file])
|
56
|
+
|
57
|
+
delete_tmpfiles(outfiles)
|
65
58
|
|
66
59
|
exit(status.exitstatus)
|
67
60
|
end
|
@@ -69,19 +62,19 @@ class SourceWindowsBatch
|
|
69
62
|
private
|
70
63
|
|
71
64
|
def parse_args!(argv)
|
72
|
-
|
65
|
+
args = {}
|
73
66
|
while argv.length > 0 && argv[0].start_with?("-")
|
74
67
|
arg = argv.shift
|
75
68
|
case arg
|
76
69
|
when "--"
|
77
70
|
next
|
78
|
-
when "--show-
|
79
|
-
|
71
|
+
when "--show-tmpfiles"
|
72
|
+
args[:show_tmpfiles] = true
|
80
73
|
when "--preserve-dump"
|
81
|
-
|
74
|
+
args[:preserve_dump] = true
|
82
75
|
when "--debug"
|
83
|
-
|
84
|
-
|
76
|
+
args[:preserve_dump] = true
|
77
|
+
args[:show_tmpfiles] = true
|
85
78
|
when "--help", "-h"
|
86
79
|
puts help
|
87
80
|
exit
|
@@ -98,65 +91,39 @@ class SourceWindowsBatch
|
|
98
91
|
STDERR.puts help
|
99
92
|
exit 1
|
100
93
|
end
|
94
|
+
|
95
|
+
args[:env_sync_file] = argv[0]
|
96
|
+
args[:macro_sync_file] = argv[1]
|
97
|
+
args[:cwd_sync_file] = argv[2]
|
98
|
+
args[:win_cmd] = argv[3..-1].join(" ")
|
101
99
|
|
102
|
-
|
100
|
+
args
|
103
101
|
end
|
104
102
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
Usage:
|
112
|
-
sw [ [sw_options] -- ] win_bat_file [args...]
|
113
|
-
|
114
|
-
Sw options:
|
115
|
-
-h --help Show this help message
|
116
|
-
-v --version Show the version information
|
117
|
-
--preserve-dump Preserve the environment dump files of cmd.exe for
|
118
|
-
debugging
|
119
|
-
--show-cmd Show the command executed in cmd.exe for debugging
|
120
|
-
--debug Enable '--preserve-dump' and '--show-cmd' options
|
121
|
-
|
122
|
-
Examples:
|
123
|
-
sw echo test
|
124
|
-
sw somebat.bat
|
125
|
-
|
126
|
-
You can control some behavior of SourceWinBat by defining following environment
|
127
|
-
variables.
|
128
|
-
|
129
|
-
Blacklisting and Whitelisting Environment Variable Not to be Synced:
|
130
|
-
|
131
|
-
SWB_BLACKLIST Define comma-separated environment variable names with
|
132
|
-
regular expressions. All environment variables included
|
133
|
-
in this list will not be synced by SourceWinBat.
|
134
|
-
|
135
|
-
SWB_WHITELIST Define variable names in the same manner as that of
|
136
|
-
SWB_BLACKLIST. All environment variables that are NOT
|
137
|
-
included in the list will NOT be synced by SourceWinBat.
|
138
|
-
|
139
|
-
Examples:
|
140
|
-
|
141
|
-
export SWB_BLACKLIST="foo:bar:baz_.*"
|
142
|
-
|
143
|
-
"foo", "bar", and any variables name of which start with "baz_" will not
|
144
|
-
be synced
|
145
|
-
|
146
|
-
export SWB_BLACKLIST="sync_taboo"
|
147
|
-
export SWB_WHITELIST="sync_.*"
|
103
|
+
def parse_option_envs()
|
104
|
+
options = {}
|
105
|
+
if ENV["SWB_DEBUG"] == "1"
|
106
|
+
options[:show_tmpfiles] = true
|
107
|
+
options[:preserve_dump] = true
|
108
|
+
end
|
148
109
|
|
149
|
-
|
150
|
-
except "sync_taboo".
|
151
|
-
EOS
|
110
|
+
options
|
152
111
|
end
|
153
112
|
|
154
|
-
def
|
113
|
+
def detect_codepage
|
155
114
|
if !STDOUT.isatty && UnixCompatEnv.compat_env == :wsl
|
156
|
-
# cmd.exe seems to use UTF-8 when Stdout is redirected in WSL.
|
115
|
+
# cmd.exe seems to use UTF-8 when Stdout is redirected in WSL.
|
116
|
+
# TODO: Is it always fixed?
|
157
117
|
return "65001" # CP65001 is UTF-8
|
158
118
|
end
|
159
119
|
|
120
|
+
return ENV['SWB_CODEPAGE_CACHE'] if ENV['SWB_CODEPAGE_CACHE']
|
121
|
+
|
122
|
+
# You cannot detect the codepage by chcp because
|
123
|
+
# 1. chcp always retuns 65001 if it's not in a tty
|
124
|
+
# 2. you cannot get the output of a windows exe by Ruby's PTY module
|
125
|
+
# for some reason.
|
126
|
+
# So, we use powershell instead here.
|
160
127
|
posh_cmd = <<-EOS
|
161
128
|
Get-WinSystemLocale | Select-Object Name, DisplayName,
|
162
129
|
@{ n='OEMCP'; e={ $_.TextInfo.OemCodePage } },
|
@@ -165,9 +132,22 @@ EOS
|
|
165
132
|
posh_res = `powershell.exe "#{posh_cmd.gsub("$", "\\$")}"`
|
166
133
|
locale = posh_res.lines.select {|line| !(line =~ /^\s*$/)}[-1].chomp
|
167
134
|
ansi_cp = locale.split(" ")[-1]
|
135
|
+
|
136
|
+
ENV['SWB_CODEPAGE_CACHE'] = ansi_cp
|
137
|
+
|
168
138
|
ansi_cp
|
169
139
|
end
|
170
140
|
|
141
|
+
def load_codepage
|
142
|
+
@codepage = detect_codepage()
|
143
|
+
@file_enc_opts = {
|
144
|
+
invalid: :replace,
|
145
|
+
undef: :replace,
|
146
|
+
replace: "?",
|
147
|
+
encoding: "CP#{@codepage}:UTF-8"
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
171
151
|
def serialize_wslenvs(wslenvs)
|
172
152
|
wslenvs.map {|varname, opt| "#{varname}#{opt.empty? ? "" : "/#{opt}"}"}.join(":")
|
173
153
|
end
|
@@ -197,22 +177,72 @@ EOS
|
|
197
177
|
false
|
198
178
|
end
|
199
179
|
|
180
|
+
def detect_diffcase_vars(var_hash)
|
181
|
+
same_names = Hash[]
|
182
|
+
var_hash.each do |name, val|
|
183
|
+
same_names[name.upcase] ||= []
|
184
|
+
same_names[name.upcase].push(name)
|
185
|
+
end
|
186
|
+
same_names.select! {|name, val| val.length > 1}
|
187
|
+
|
188
|
+
same_names
|
189
|
+
end
|
190
|
+
|
191
|
+
###
|
192
|
+
# Handling of environment variable in WSL is tricky due to WSLENV's strange behavior.
|
193
|
+
# SWB has several rules to pass UNIX environment variables to Windows.
|
194
|
+
# 1. Normally, pass a variable by running initialization batch script before
|
195
|
+
# executing the target user batch file. The initialization script contains
|
196
|
+
# `set` statements generated by SWB.
|
197
|
+
#
|
198
|
+
# 2. If a variable contains characters that need escaping, such as '|', '>',
|
199
|
+
# pass it by WSLENV.
|
200
|
+
# Why not passing all variables by WSLENV?
|
201
|
+
# a. It's because WSLENV has strange bahavior about case-sensitiveness.
|
202
|
+
# WSLENV syncs variables in a case-sensitive manner, even though Windows
|
203
|
+
# apps handle environment variables do not.
|
204
|
+
# For example, PATH variable is sometimes 'Path' in Windows. So, WSLENV fails
|
205
|
+
# to sync Path with Unix's PATH. Syncing by running initialization batch script
|
206
|
+
# in Windows environment can avoid this.
|
207
|
+
# b. However, I couldn't find a complete way to escape a value of a variable.
|
208
|
+
# Without escaping, set statements gets crazy like `set hoge=foo | bar`, when
|
209
|
+
# variable `hoge` has a value of `foo | bar`. So, we cannot fully depend on
|
210
|
+
# initialization batch script. That's why SWB uses combination of initialization
|
211
|
+
# script and WSLENV.
|
212
|
+
#
|
213
|
+
# 3. If a variable exists in WSLENV in the first place, sync it by WSLENV.
|
214
|
+
# A user may set some flags in WSLENV.
|
215
|
+
#
|
216
|
+
# Additionally, after completing execution of the target user batch file, if SWB
|
217
|
+
# finds some variables the names of which differ only in case, SWB shows warning.
|
218
|
+
#
|
219
|
+
# Handling of environment variable in MSYS2 and Cygwin is simple.
|
220
|
+
# They sync environment variables without any effort.
|
221
|
+
###
|
200
222
|
def prepare_env_vars
|
201
|
-
|
223
|
+
env = Hash[ENV]
|
224
|
+
return [{}, env] if UnixCompatEnv.compat_env != :wsl
|
202
225
|
|
203
|
-
|
204
|
-
|
226
|
+
chars_to_escape = /[><|&^%]/
|
227
|
+
vars = Hash[]
|
228
|
+
wslenvs = parse_wslenv(ENV['WSLENV'] || "")
|
229
|
+
ENV.each do |envvar_name, val|
|
205
230
|
next if whitelist_block?(envvar_name) || blacklist_block?(envvar_name)
|
206
|
-
wslenvs
|
231
|
+
next if wslenvs.has_key?(envvar_name)
|
232
|
+
if chars_to_escape =~ val
|
233
|
+
wslenvs[envvar_name] = ""
|
234
|
+
else
|
235
|
+
vars[envvar_name] = val
|
236
|
+
end
|
207
237
|
end
|
208
|
-
|
209
|
-
#
|
210
|
-
#
|
211
|
-
wslenvs['PATH'] = ""
|
212
|
-
|
238
|
+
# We don't use WSLENV for Path, but convert paths by ourselves instead.
|
239
|
+
# So, set it to empty. WSLENV is restored to the original value in Windows
|
240
|
+
# environment by the initialization script
|
241
|
+
wslenvs['PATH'] = "" if wslenvs['PATH']
|
242
|
+
env['WSLENV'] = serialize_wslenvs(wslenvs) if !wslenvs.empty?
|
213
243
|
|
214
244
|
paths = []
|
215
|
-
ENV['PATH'].split(
|
245
|
+
ENV['PATH'].split(':').each do |path|
|
216
246
|
begin
|
217
247
|
rpath = File.realpath(path)
|
218
248
|
if rpath.start_with?(UnixCompatEnv.win_root_in_compat)
|
@@ -222,28 +252,92 @@ EOS
|
|
222
252
|
end
|
223
253
|
paths.push(path)
|
224
254
|
end
|
225
|
-
|
255
|
+
vars['PATH'] = paths.join(';')
|
256
|
+
|
257
|
+
if !(same_names = detect_diffcase_vars(vars.merge(wslenvs))).empty?
|
258
|
+
error_mes = <<-EOS
|
259
|
+
SWB Error:
|
260
|
+
You have environment variables the names of which differ only in case.
|
261
|
+
SWB cannot preserve and restore them due to case insensitiveness of Windows.
|
262
|
+
Please undefine them or add either to SWB_BLACKLIST to prevent ambiguity.
|
263
|
+
Ambiguous variables:
|
264
|
+
EOS
|
265
|
+
same_names.each do |_, vals|
|
266
|
+
error_mes += " - " + vals.join(", ") + "\n"
|
267
|
+
end
|
268
|
+
raise CaseSensitiveVariableError.new(error_mes)
|
269
|
+
end
|
226
270
|
|
227
|
-
|
271
|
+
[vars, env]
|
228
272
|
end
|
229
273
|
|
230
274
|
def mk_tmpname(suffix)
|
231
275
|
"#{UnixCompatEnv.win_tmp_in_compat}#{SecureRandom.uuid + suffix}"
|
232
276
|
end
|
233
277
|
|
234
|
-
def
|
235
|
-
|
278
|
+
def make_envsync_cmd(cmd)
|
279
|
+
files = {}
|
280
|
+
|
281
|
+
begin
|
282
|
+
wrapper_batch_file = mk_tmpname(".cmd")
|
283
|
+
File.write(wrapper_batch_file, "@" + cmd)
|
284
|
+
files[:wrapper_batch_file] = wrapper_batch_file
|
285
|
+
|
286
|
+
statements = ["@call " + dq_win_path(UnixCompatEnv.to_win_path(wrapper_batch_file))]
|
287
|
+
|
288
|
+
statements.push("@set SWB_EXITSTATUS=%errorlevel%")
|
289
|
+
proc_env = concat_env_init!(statements, files)
|
290
|
+
concat_env_dump!(statements, files)
|
291
|
+
concat_macro_dump!(statements, files)
|
292
|
+
concat_cwd_dump!(statements, files)
|
293
|
+
statements.push("@exit %SWB_EXITSTATUS%")
|
294
|
+
|
295
|
+
internal_command_file = mk_tmpname(".cmd")
|
296
|
+
File.write(internal_command_file, statements.join("\r\n"))
|
297
|
+
files[:internal_command_file] = internal_command_file
|
298
|
+
internal_command = "@" + dq_win_path(UnixCompatEnv.to_win_path(internal_command_file))
|
299
|
+
|
300
|
+
[internal_command, files, proc_env]
|
301
|
+
rescue CaseSensitiveVariableError => e
|
302
|
+
STDERR.puts e.message
|
303
|
+
delete_tmpfiles(files)
|
304
|
+
exit(1)
|
305
|
+
end
|
236
306
|
end
|
237
307
|
|
238
|
-
def
|
308
|
+
def concat_env_init!(statements, outfiles)
|
309
|
+
vars_to_sync, proc_env = prepare_env_vars
|
310
|
+
|
311
|
+
env_init_file = mk_tmpname(".cmd")
|
312
|
+
File.write(env_init_file,
|
313
|
+
vars_to_sync.map {|var, val| "@set #{var}=#{val}"}.join("\r\n"),
|
314
|
+
opt=@file_enc_opts)
|
315
|
+
outfiles[:env_init_file] = env_init_file
|
316
|
+
|
317
|
+
statements.unshift("@call " + dq_win_path(UnixCompatEnv.to_win_path(env_init_file)))
|
318
|
+
|
319
|
+
proc_env
|
320
|
+
end
|
321
|
+
|
322
|
+
def concat_env_dump!(statements, outfiles)
|
323
|
+
env_windump_file = mk_tmpname(".env")
|
324
|
+
statements.push("@set > #{dq_win_path(UnixCompatEnv.to_win_path(env_windump_file))}")
|
325
|
+
outfiles[:env_windump_file] = env_windump_file
|
326
|
+
end
|
327
|
+
|
328
|
+
def concat_macro_dump!(statements, outfiles)
|
329
|
+
macro_windump_file = mk_tmpname(".doskey")
|
239
330
|
#TODO: escape
|
240
|
-
|
331
|
+
statements.push("@doskey /macros > #{dq_win_path(UnixCompatEnv.to_win_path(macro_windump_file))}")
|
332
|
+
outfiles[:macro_windump_file] = macro_windump_file
|
241
333
|
end
|
242
334
|
|
243
|
-
def
|
335
|
+
def concat_cwd_dump!(statements, outfiles)
|
336
|
+
cwd_windump_file = mk_tmpname(".cwd")
|
244
337
|
#TODO: escape
|
245
|
-
winpath = dq_win_path(UnixCompatEnv.to_win_path(
|
246
|
-
|
338
|
+
winpath = dq_win_path(UnixCompatEnv.to_win_path(cwd_windump_file))
|
339
|
+
statements.push("@ cd > #{winpath} & pushd >> #{winpath}")
|
340
|
+
outfiles[:cwd_windump_file] = cwd_windump_file
|
247
341
|
end
|
248
342
|
|
249
343
|
def dq_win_path(str)
|
@@ -257,78 +351,65 @@ EOS
|
|
257
351
|
str.gsub(/'/, '"\'"')
|
258
352
|
end
|
259
353
|
|
260
|
-
def to_compat_pathlist(path
|
261
|
-
raise "Unsupporeted" unless shell == :bash
|
354
|
+
def to_compat_pathlist(path)
|
262
355
|
path.split(";")
|
263
356
|
.map {|p| UnixCompatEnv.to_compat_path(p)}
|
264
357
|
.join(":")
|
265
358
|
end
|
266
359
|
|
267
|
-
def
|
268
|
-
|
269
|
-
var, val = /([^=]*)=(.*)$/.match(set_stmt)[1..2]
|
270
|
-
|
271
|
-
is_var_valid = /^[a-zA-Z_][_0-9a-zA-Z]*$/ =~ var
|
272
|
-
return nil unless is_var_valid
|
273
|
-
|
274
|
-
if var == "PATH" && UnixCompatEnv.compat_env != :wsl
|
275
|
-
val = to_compat_pathlist(val, :bash)
|
276
|
-
end
|
277
|
-
|
278
|
-
stmt = "export #{var}='#{escape_singlequote(val.chomp)}'"
|
279
|
-
return stmt if UnixCompatEnv.compat_env != :wsl
|
280
|
-
|
281
|
-
if var == "PATH"
|
282
|
-
stmt += "\nexport WSLENV=PATH/l:${WSLENV:-__EC_DUMMY_ENV}"
|
283
|
-
else
|
284
|
-
stmt += "\nexport WSLENV=#{var}:${WSLENV:-__EC_DUMMY_ENV}"
|
285
|
-
end
|
286
|
-
stmt
|
287
|
-
end
|
288
|
-
|
289
|
-
def conv_setenv_stmts(setenvfile, outfile, shell, codepage)
|
290
|
-
raise "Unsupporeted" if shell != :bash
|
360
|
+
def conv_setenv_stmts(setenvfile, outfile)
|
361
|
+
return if !File.exist?(setenvfile)
|
291
362
|
|
363
|
+
vars = Hash[]
|
364
|
+
envs_casemap = Hash[ENV.keys.map {|k| [k.upcase, k]}]
|
292
365
|
File.open(outfile, "w") do |f_out|
|
293
|
-
|
294
|
-
|
295
|
-
var, val = /([^=]*)=(.*)$/.match(set_stmt)[1..2]
|
366
|
+
File.read(setenvfile, opt=@file_enc_opts).lines.each do |set_stmt|
|
367
|
+
var, val = /([^=]*)=(.*)$/.match(set_stmt)[1..2]
|
296
368
|
|
297
369
|
is_var_valid = /^[a-zA-Z_][_0-9a-zA-Z]*$/ =~ var
|
298
370
|
next if !is_var_valid
|
299
371
|
next if whitelist_block?(var) || blacklist_block?(var)
|
372
|
+
vars[var] = val
|
300
373
|
|
301
|
-
|
302
|
-
val = to_compat_pathlist(val
|
374
|
+
if var.upcase == "PATH"
|
375
|
+
val = to_compat_pathlist(val)
|
303
376
|
end
|
304
377
|
|
305
|
-
|
378
|
+
var = envs_casemap[var.upcase] || var
|
306
379
|
f_out.puts("export #{var}='#{escape_singlequote(val.chomp)}'")
|
307
380
|
end
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
381
|
+
end
|
382
|
+
|
383
|
+
if !(same_names = detect_diffcase_vars(vars)).empty?
|
384
|
+
STDERR.puts <<-EOS
|
385
|
+
SWB Warning:
|
386
|
+
You've synced the environment variables the names of which differ only
|
387
|
+
in case. That means one of the following.
|
388
|
+
1. You define a variable in your WSLENV, and your Windows environment
|
389
|
+
has another variable the name of which differ only in case.
|
390
|
+
2. SWB synced a variable by WSLENV, and your Windows command defined
|
391
|
+
another variable the name of which differ only in case from that of
|
392
|
+
the variable SWB synced.
|
393
|
+
SWB normally syncs variables by initialization script. However, if
|
394
|
+
a variable's value contains special character to be escaped, SWB
|
395
|
+
syncs it by WSLENV instead. That is the case here.
|
396
|
+
|
397
|
+
To solve this warning, please undefine those variables, or add them, except
|
398
|
+
one variable, to SWB_BLACKLIST to prevent ambiguity.
|
399
|
+
Ambiguous variables:
|
400
|
+
EOS
|
401
|
+
same_names.each do |_, vals|
|
402
|
+
STDERR.puts(" - " + vals.join(", "))
|
323
403
|
end
|
324
404
|
end
|
405
|
+
|
325
406
|
end
|
326
407
|
|
327
|
-
def conv_doskey_stmts(doskeyfile, outfile
|
328
|
-
|
408
|
+
def conv_doskey_stmts(doskeyfile, outfile)
|
409
|
+
return if !File.exist?(doskeyfile)
|
329
410
|
|
330
411
|
File.open(outfile, "w") do |f_out|
|
331
|
-
File.open(doskeyfile,
|
412
|
+
File.open(doskeyfile, opt=@file_enc_opts) do |f_in|
|
332
413
|
f_in.each_line do |doskey_stmt|
|
333
414
|
key, body = /([^=]*)=(.*)$/.match(doskey_stmt)[1..2]
|
334
415
|
|
@@ -348,11 +429,10 @@ EOS
|
|
348
429
|
end
|
349
430
|
end
|
350
431
|
|
351
|
-
def gen_chdir_cmds(dirs, outfile
|
352
|
-
|
353
|
-
return unless File.exist?(dirs)
|
432
|
+
def gen_chdir_cmds(dirs, outfile)
|
433
|
+
return if !File.exist?(dirs)
|
354
434
|
|
355
|
-
lines = File.read(dirs,
|
435
|
+
lines = File.read(dirs, opt=@file_enc_opts).lines.select {|line| !line.empty?}
|
356
436
|
cwd = lines[0]
|
357
437
|
dirs = lines[1..-1]
|
358
438
|
|
@@ -365,4 +445,91 @@ EOS
|
|
365
445
|
File.write(outfile, res.join("\n"))
|
366
446
|
end
|
367
447
|
|
448
|
+
def log_file_content(file_type, filename)
|
449
|
+
STDERR.puts("=== begin: #{file_type} ===\n")
|
450
|
+
if File.exist?(filename)
|
451
|
+
STDERR.puts("=== - CP#{@codepage}:'#{filename}' ===\n")
|
452
|
+
STDERR.puts(File.read(filename, opt=@file_enc_opts))
|
453
|
+
else
|
454
|
+
STDERR.puts("This file doesn't exist.")
|
455
|
+
STDERR.puts("Maybe Windows command terminated by exit command")
|
456
|
+
end
|
457
|
+
STDERR.puts("=== end: #{file_type} ===\n")
|
458
|
+
end
|
459
|
+
|
460
|
+
def delete_tmpfiles(tmpfiles)
|
461
|
+
tmpfiles.each do |k, f|
|
462
|
+
if @args[:show_tmpfiles]
|
463
|
+
log_file_content(k, f)
|
464
|
+
end
|
465
|
+
if !@args[:preserve_dump]
|
466
|
+
File.delete(f) if File.exist?(f)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def help
|
472
|
+
<<EOS
|
473
|
+
sw, or SourceWinBat, is a utility to run Windows batch files from WSL /
|
474
|
+
MSYS2 / Cygwin and sync environment variables, and working directories
|
475
|
+
between batch files and their UNIX Bash shell.
|
476
|
+
|
477
|
+
Usage:
|
478
|
+
sw [ [sw_options] -- ] win_bat_file [args...]
|
479
|
+
|
480
|
+
Sw options:
|
481
|
+
-h --help Show this help message
|
482
|
+
-v --version Show the version information
|
483
|
+
--preserve-dump Preserve the environment dump files of cmd.exe for
|
484
|
+
debugging
|
485
|
+
--show-tmpfiles Show the contents of the temporary files such as
|
486
|
+
the environment dump files
|
487
|
+
--debug Enable '--preserve-dump', '--show-tmpfiles' options
|
488
|
+
|
489
|
+
Examples:
|
490
|
+
sw echo test
|
491
|
+
sw somebat.bat
|
492
|
+
|
493
|
+
You can control some behavior of SourceWinBat by defining following environment
|
494
|
+
variables.
|
495
|
+
|
496
|
+
Blacklisting and Whitelisting Environment Variable Not to be Synced:
|
497
|
+
|
498
|
+
SWB_BLACKLIST Define comma-separated environment variable names with
|
499
|
+
regular expressions. All environment variables included
|
500
|
+
in this list will not be synced by SourceWinBat.
|
501
|
+
|
502
|
+
SWB_WHITELIST Define variable names in the same manner as that of
|
503
|
+
SWB_BLACKLIST. All environment variables that are NOT
|
504
|
+
included in the list will NOT be synced by SourceWinBat.
|
505
|
+
|
506
|
+
Examples:
|
507
|
+
|
508
|
+
export SWB_BLACKLIST="foo:bar:baz_.*"
|
509
|
+
|
510
|
+
"foo", "bar", and any variables name of which start with "baz_" will not
|
511
|
+
be synced
|
512
|
+
|
513
|
+
export SWB_BLACKLIST="sync_taboo"
|
514
|
+
export SWB_WHITELIST="sync_.*"
|
515
|
+
|
516
|
+
Only variables name of which start with "sync_" will be synced,
|
517
|
+
except "sync_taboo".
|
518
|
+
|
519
|
+
## Several things to keep in mind:
|
520
|
+
|
521
|
+
1. SourceWinBat executes the given Windows command in "Batch file mode".
|
522
|
+
|
523
|
+
Windows cmd.exe has a few different behaviors in the interactive
|
524
|
+
"command line mode" and the "batch file mode". For example, expansion
|
525
|
+
result of an empty variable, or variable expansion in for command.
|
526
|
+
SourceWinBat executes the given command always in the batch file mode.
|
527
|
+
|
528
|
+
2. `exit` command prevents SourceWinBat from synciny environment variables.
|
529
|
+
|
530
|
+
If you can fix the batch file you run, please replace `exit` with `exit /B`
|
531
|
+
|
532
|
+
EOS
|
533
|
+
end
|
534
|
+
|
368
535
|
end
|
data/source_win_bat.gemspec
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
source ./setup_test.bash
|
4
|
+
tap_tests 12
|
5
|
+
|
6
|
+
export DIFFCASE1=FOO
|
7
|
+
[[ $(sw echo %DiffCase1%) =~ FOO ]]; tap_okif $? "Test a variable of different cases can be read in Windows 1"
|
8
|
+
export DiffCase2=FOO
|
9
|
+
[[ $(sw echo %DIFFCASE2%) =~ FOO ]]; tap_okif $? "Test a variable of different cases can be read in Windows 2"
|
10
|
+
[[ -z "$DIFFCASE3" ]]; tap_okif $? "Test a variable is undefined 1"
|
11
|
+
[[ -z "$DiffCase3" ]]; tap_okif $? "Test a variable is undefined 2"
|
12
|
+
|
13
|
+
sw set_diff_case_env.cmd
|
14
|
+
|
15
|
+
[[ "$DIFFCASE1" =~ BAR ]]; tap_okif $? "Test a variable of different cases is modified in Windows 1"
|
16
|
+
[[ -z "$DiffCase1" ]]; tap_okif $? "Test a variable of different cases merges 1"
|
17
|
+
[[ "$DiffCase2" =~ BAR ]]; tap_okif $? "Test a variable of different cases is modified in Windows 2"
|
18
|
+
[[ "$DiffCase3" =~ BAR ]]; tap_okif $? "Test a variable of different cases is modified in Windows 3"
|
19
|
+
[[ -z "$DIFFCASE3" ]]; tap_okif $? "Test a variable is undefined 3"
|
20
|
+
|
21
|
+
unset DiffCase3
|
22
|
+
export DIFFCASE3=BAZ
|
23
|
+
[[ $(sw echo %DiffCase3%) =~ BAZ ]]; tap_okif $? "Test a variable of different cases merges 1"
|
24
|
+
[[ $(echo $DIFFCASE3) =~ BAZ ]]; tap_okif $? "Test a variable of different cases merges 2"
|
25
|
+
[[ -z "$DiffCase3" ]]; tap_okif $? "Test a variable of different cases merges 3"
|
26
|
+
|
data/test/test_setdoskey.bash
CHANGED
@@ -5,11 +5,11 @@ tap_tests 4
|
|
5
5
|
|
6
6
|
sw setdoskey.cmd
|
7
7
|
|
8
|
-
expected="bar
|
8
|
+
expected="bar"
|
9
9
|
[[ $(foo) =~ $expected ]]; tap_okif $?
|
10
|
-
expected="foo
|
10
|
+
expected="foo"
|
11
11
|
[[ $(echo1stparam foo bar) =~ $expected ]]; tap_okif $?
|
12
|
-
expected="foo bar
|
12
|
+
expected="foo bar"
|
13
13
|
[[ $(echoallparams foo bar) =~ $expected ]]; tap_okif $?
|
14
14
|
expected="Microsoft Windows"
|
15
15
|
[[ $(verver) =~ $expected ]]; tap_okif $?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: source_win_bat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takaya Saeki
|
@@ -25,15 +25,16 @@ files:
|
|
25
25
|
- bin/init_sw
|
26
26
|
- lib/source_win_bat.rb
|
27
27
|
- lib/unixcompatenv.rb
|
28
|
-
- source_win_bat-0.1.0.gem
|
29
28
|
- source_win_bat.gemspec
|
30
29
|
- test/exit_42.cmd
|
30
|
+
- test/set_diff_case_env.cmd
|
31
31
|
- test/setcwd.cmd
|
32
32
|
- test/setdoskey.cmd
|
33
33
|
- test/setenv.cmd
|
34
34
|
- test/setup_test.bash
|
35
35
|
- test/tap.bash
|
36
36
|
- test/test_ansicpchars.bash
|
37
|
+
- test/test_diffrent_case_envvar_bug.bash
|
37
38
|
- test/test_exit.bash
|
38
39
|
- test/test_optionparsebug.bash
|
39
40
|
- test/test_setcwd.bash
|
data/source_win_bat-0.1.0.gem
DELETED
Binary file
|