childprocess 4.1.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +32 -0
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile +3 -2
  5. data/README.md +5 -23
  6. data/childprocess.gemspec +2 -0
  7. data/lib/childprocess/abstract_process.rb +1 -1
  8. data/lib/childprocess/errors.rb +0 -21
  9. data/lib/childprocess/process_spawn_process.rb +127 -0
  10. data/lib/childprocess/unix/process.rb +3 -64
  11. data/lib/childprocess/unix.rb +2 -4
  12. data/lib/childprocess/version.rb +1 -1
  13. data/lib/childprocess/windows/process.rb +13 -116
  14. data/lib/childprocess/windows.rb +0 -29
  15. data/lib/childprocess.rb +16 -53
  16. data/spec/childprocess_spec.rb +39 -15
  17. data/spec/io_spec.rb +1 -1
  18. data/spec/spec_helper.rb +5 -20
  19. data/spec/unix_spec.rb +3 -7
  20. metadata +19 -24
  21. data/.travis.yml +0 -37
  22. data/appveyor.yml +0 -36
  23. data/lib/childprocess/jruby/io.rb +0 -16
  24. data/lib/childprocess/jruby/process.rb +0 -184
  25. data/lib/childprocess/jruby/pump.rb +0 -53
  26. data/lib/childprocess/jruby.rb +0 -56
  27. data/lib/childprocess/tools/generator.rb +0 -146
  28. data/lib/childprocess/unix/fork_exec_process.rb +0 -78
  29. data/lib/childprocess/unix/lib.rb +0 -186
  30. data/lib/childprocess/unix/platform/arm64-macosx.rb +0 -11
  31. data/lib/childprocess/unix/platform/i386-linux.rb +0 -12
  32. data/lib/childprocess/unix/platform/i386-solaris.rb +0 -11
  33. data/lib/childprocess/unix/platform/x86_64-linux.rb +0 -12
  34. data/lib/childprocess/unix/platform/x86_64-macosx.rb +0 -11
  35. data/lib/childprocess/unix/posix_spawn_process.rb +0 -134
  36. data/lib/childprocess/windows/handle.rb +0 -91
  37. data/lib/childprocess/windows/lib.rb +0 -416
  38. data/lib/childprocess/windows/process_builder.rb +0 -178
  39. data/lib/childprocess/windows/structs.rb +0 -149
  40. data/spec/jruby_spec.rb +0 -24
@@ -1,178 +0,0 @@
1
- module ChildProcess
2
- module Windows
3
- class ProcessBuilder
4
- attr_accessor :leader, :detach, :duplex, :environment, :stdout, :stderr, :cwd
5
- attr_reader :stdin
6
-
7
- def initialize(args)
8
- @args = args
9
-
10
- @detach = false
11
- @duplex = false
12
- @environment = nil
13
- @cwd = nil
14
-
15
- @stdout = nil
16
- @stderr = nil
17
- @stdin = nil
18
-
19
- @flags = 0
20
- @job_ptr = nil
21
- @cmd_ptr = nil
22
- @env_ptr = nil
23
- @cwd_ptr = nil
24
- end
25
-
26
- def start
27
- create_command_pointer
28
- create_environment_pointer
29
- create_cwd_pointer
30
-
31
- setup_flags
32
- setup_io
33
-
34
- pid = create_process
35
- close_handles
36
-
37
- pid
38
- end
39
-
40
- private
41
-
42
- def to_wide_string(str)
43
- newstr = str + "\0".encode(str.encoding)
44
- newstr.encode!('UTF-16LE')
45
- end
46
-
47
- def create_command_pointer
48
- string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join(' ')
49
- @cmd_ptr = to_wide_string(string)
50
- end
51
-
52
- def create_environment_pointer
53
- return unless @environment.kind_of?(Hash) && @environment.any?
54
-
55
- strings = []
56
-
57
- ENV.to_hash.merge(@environment).each do |key, val|
58
- next if val.nil?
59
-
60
- if key.to_s =~ /=|\0/ || val.to_s.include?("\0")
61
- raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}"
62
- end
63
-
64
- strings << "#{key}=#{val}\0"
65
- end
66
-
67
- env_str = to_wide_string(strings.join)
68
- @env_ptr = FFI::MemoryPointer.from_string(env_str)
69
- end
70
-
71
- def create_cwd_pointer
72
- @cwd_ptr = FFI::MemoryPointer.from_string(to_wide_string(@cwd || Dir.pwd))
73
- end
74
-
75
- def create_process
76
- ok = Lib.create_process(
77
- nil, # application name
78
- @cmd_ptr, # command line
79
- nil, # process attributes
80
- nil, # thread attributes
81
- true, # inherit handles
82
- @flags, # creation flags
83
- @env_ptr, # environment
84
- @cwd_ptr, # current directory
85
- startup_info, # startup info
86
- process_info # process info
87
- )
88
-
89
- ok or raise LaunchError, Lib.last_error_message
90
-
91
- process_info[:dwProcessId]
92
- end
93
-
94
- def startup_info
95
- @startup_info ||= StartupInfo.new
96
- end
97
-
98
- def process_info
99
- @process_info ||= ProcessInfo.new
100
- end
101
-
102
- def setup_flags
103
- @flags |= CREATE_UNICODE_ENVIRONMENT
104
- @flags |= DETACHED_PROCESS if @detach
105
- @flags |= CREATE_BREAKAWAY_FROM_JOB if @leader
106
- end
107
-
108
- def setup_io
109
- startup_info[:dwFlags] ||= 0
110
- startup_info[:dwFlags] |= STARTF_USESTDHANDLES
111
-
112
- if @stdout
113
- startup_info[:hStdOutput] = std_stream_handle_for(@stdout)
114
- end
115
-
116
- if @stderr
117
- startup_info[:hStdError] = std_stream_handle_for(@stderr)
118
- end
119
-
120
- if @duplex
121
- read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
122
- write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
123
- sa = SecurityAttributes.new(:inherit => true)
124
-
125
- ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
126
- Lib.check_error ok
127
-
128
- @read_pipe = read_pipe_ptr.read_pointer
129
- @write_pipe = write_pipe_ptr.read_pointer
130
-
131
- Lib.set_handle_inheritance @read_pipe, true
132
- Lib.set_handle_inheritance @write_pipe, false
133
-
134
- startup_info[:hStdInput] = @read_pipe
135
- else
136
- startup_info[:hStdInput] = std_stream_handle_for(STDIN)
137
- end
138
- end
139
-
140
- def std_stream_handle_for(io)
141
- handle = Lib.handle_for(io)
142
-
143
- begin
144
- Lib.set_handle_inheritance handle, true
145
- rescue ChildProcess::Error
146
- # If the IO was set to close on exec previously, this call will fail.
147
- # That's probably OK, since the user explicitly asked for it to be
148
- # closed (at least I have yet to find other cases where this will
149
- # happen...)
150
- end
151
-
152
- handle
153
- end
154
-
155
- def close_handles
156
- Lib.close_handle process_info[:hProcess]
157
- Lib.close_handle process_info[:hThread]
158
-
159
- if @duplex
160
- @stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY)
161
- Lib.close_handle @read_pipe
162
- Lib.close_handle @write_pipe
163
- end
164
- end
165
-
166
- def quote_if_necessary(str)
167
- quote = str.start_with?('"') ? "'" : '"'
168
-
169
- case str
170
- when /[\s\\'"]/
171
- [quote, str, quote].join
172
- else
173
- str
174
- end
175
- end
176
- end # ProcessBuilder
177
- end # Windows
178
- end # ChildProcess
@@ -1,149 +0,0 @@
1
- module ChildProcess
2
- module Windows
3
- # typedef struct _STARTUPINFO {
4
- # DWORD cb;
5
- # LPTSTR lpReserved;
6
- # LPTSTR lpDesktop;
7
- # LPTSTR lpTitle;
8
- # DWORD dwX;
9
- # DWORD dwY;
10
- # DWORD dwXSize;
11
- # DWORD dwYSize;
12
- # DWORD dwXCountChars;
13
- # DWORD dwYCountChars;
14
- # DWORD dwFillAttribute;
15
- # DWORD dwFlags;
16
- # WORD wShowWindow;
17
- # WORD cbReserved2;
18
- # LPBYTE lpReserved2;
19
- # HANDLE hStdInput;
20
- # HANDLE hStdOutput;
21
- # HANDLE hStdError;
22
- # } STARTUPINFO, *LPSTARTUPINFO;
23
-
24
- class StartupInfo < FFI::Struct
25
- layout :cb, :ulong,
26
- :lpReserved, :pointer,
27
- :lpDesktop, :pointer,
28
- :lpTitle, :pointer,
29
- :dwX, :ulong,
30
- :dwY, :ulong,
31
- :dwXSize, :ulong,
32
- :dwYSize, :ulong,
33
- :dwXCountChars, :ulong,
34
- :dwYCountChars, :ulong,
35
- :dwFillAttribute, :ulong,
36
- :dwFlags, :ulong,
37
- :wShowWindow, :ushort,
38
- :cbReserved2, :ushort,
39
- :lpReserved2, :pointer,
40
- :hStdInput, :pointer, # void ptr
41
- :hStdOutput, :pointer, # void ptr
42
- :hStdError, :pointer # void ptr
43
- end
44
-
45
- #
46
- # typedef struct _PROCESS_INFORMATION {
47
- # HANDLE hProcess;
48
- # HANDLE hThread;
49
- # DWORD dwProcessId;
50
- # DWORD dwThreadId;
51
- # } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
52
- #
53
-
54
- class ProcessInfo < FFI::Struct
55
- layout :hProcess, :pointer, # void ptr
56
- :hThread, :pointer, # void ptr
57
- :dwProcessId, :ulong,
58
- :dwThreadId, :ulong
59
- end
60
-
61
- #
62
- # typedef struct _SECURITY_ATTRIBUTES {
63
- # DWORD nLength;
64
- # LPVOID lpSecurityDescriptor;
65
- # BOOL bInheritHandle;
66
- # } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
67
- #
68
-
69
- class SecurityAttributes < FFI::Struct
70
- layout :nLength, :ulong,
71
- :lpSecurityDescriptor, :pointer, # void ptr
72
- :bInheritHandle, :int
73
-
74
- def initialize(opts = {})
75
- super()
76
-
77
- self[:nLength] = self.class.size
78
- self[:lpSecurityDescriptor] = nil
79
- self[:bInheritHandle] = opts[:inherit] ? 1 : 0
80
- end
81
- end
82
-
83
- #
84
- # typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
85
- # LARGE_INTEGER PerProcessUserTimeLimit;
86
- # LARGE_INTEGER PerJobUserTimeLimit;
87
- # DWORD LimitFlags;
88
- # SIZE_T MinimumWorkingSetSize;
89
- # SIZE_T MaximumWorkingSetSize;
90
- # DWORD ActiveProcessLimit;
91
- # ULONG_PTR Affinity;
92
- # DWORD PriorityClass;
93
- # DWORD SchedulingClass;
94
- # } JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
95
- #
96
- class JobObjectBasicLimitInformation < FFI::Struct
97
- layout :PerProcessUserTimeLimit, :int64,
98
- :PerJobUserTimeLimit, :int64,
99
- :LimitFlags, :ulong,
100
- :MinimumWorkingSetSize, :size_t,
101
- :MaximumWorkingSetSize, :size_t,
102
- :ActiveProcessLimit, :ulong,
103
- :Affinity, :pointer,
104
- :PriorityClass, :ulong,
105
- :SchedulingClass, :ulong
106
- end
107
-
108
- #
109
- # typedef struct _IO_COUNTERS {
110
- # ULONGLONG ReadOperationCount;
111
- # ULONGLONG WriteOperationCount;
112
- # ULONGLONG OtherOperationCount;
113
- # ULONGLONG ReadTransferCount;
114
- # ULONGLONG WriteTransferCount;
115
- # ULONGLONG OtherTransferCount;
116
- # } IO_COUNTERS, *PIO_COUNTERS;
117
- #
118
-
119
- class IoCounters < FFI::Struct
120
- layout :ReadOperationCount, :ulong_long,
121
- :WriteOperationCount, :ulong_long,
122
- :OtherOperationCount, :ulong_long,
123
- :ReadTransferCount, :ulong_long,
124
- :WriteTransferCount, :ulong_long,
125
- :OtherTransferCount, :ulong_long
126
- end
127
- #
128
- # typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
129
- # JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
130
- # IO_COUNTERS IoInfo;
131
- # SIZE_T ProcessMemoryLimit;
132
- # SIZE_T JobMemoryLimit;
133
- # SIZE_T PeakProcessMemoryUsed;
134
- # SIZE_T PeakJobMemoryUsed;
135
- # } JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
136
- #
137
-
138
- class JobObjectExtendedLimitInformation < FFI::Struct
139
- layout :BasicLimitInformation, JobObjectBasicLimitInformation,
140
- :IoInfo, IoCounters,
141
- :ProcessMemoryLimit, :size_t,
142
- :JobMemoryLimit, :size_t,
143
- :PeakProcessMemoryUsed, :size_t,
144
- :PeakJobMemoryUsed, :size_t
145
- end
146
-
147
-
148
- end # Windows
149
- end # ChildProcess
data/spec/jruby_spec.rb DELETED
@@ -1,24 +0,0 @@
1
- require File.expand_path('../spec_helper', __FILE__)
2
- require "pid_behavior"
3
-
4
- if ChildProcess.jruby? && !ChildProcess.windows?
5
- describe ChildProcess::JRuby::IO do
6
- let(:io) { ChildProcess::JRuby::IO.new }
7
-
8
- it "raises an ArgumentError if given IO does not respond to :to_outputstream" do
9
- expect { io.stdout = nil }.to raise_error(ArgumentError)
10
- end
11
- end
12
-
13
- describe ChildProcess::JRuby::Process do
14
- if ChildProcess.unix?
15
- it_behaves_like "a platform that provides the child's pid"
16
- else
17
- it "raises an error when trying to access the child's pid" do
18
- process = exit_with(0)
19
- process.start
20
- expect { process.pid }.to raise_error(NotImplementedError)
21
- end
22
- end
23
- end
24
- end