source_win_bat 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|