childprocess 4.1.0 → 5.1.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.
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