Skip to content

Commit

Permalink
Showing 21 changed files with 383 additions and 86 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyFile.java
Original file line number Diff line number Diff line change
@@ -1640,7 +1640,7 @@ else if ( ( preFix.equals("uri:classloader:") || preFix.equals("classpath:") )
if (path.startsWith("uri:")) {
cwd = path;
} else {
cwd = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[1])).getUnicodeValue();
cwd = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[1])).toString();

// Handle ~user paths.
if (expandUser) {
31 changes: 22 additions & 9 deletions core/src/main/java/org/jruby/RubyGlobal.java
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@
import org.jruby.util.OSEnvironment;
import org.jruby.util.RegexpOptions;
import org.jruby.util.cli.OutputStrings;
import org.jruby.util.io.EncodingUtils;
import org.jruby.util.io.OpenFile;
import org.jruby.util.io.STDIO;

@@ -420,9 +421,9 @@ protected IRubyObject case_aware_op_aset(ThreadContext context,
return super.delete(context, key, org.jruby.runtime.Block.NULL_BLOCK);
}

IRubyObject keyAsStr = normalizeEnvString(Helpers.invoke(context, key, "to_str"));
IRubyObject keyAsStr = normalizeEnvString(context, key, Helpers.invoke(context, key, "to_str"));
IRubyObject valueAsStr = value.isNil() ? context.nil :
normalizeEnvString(Helpers.invoke(context, value, "to_str"));
normalizeEnvString(context, key, Helpers.invoke(context, value, "to_str"));

if (updateRealENV) {
POSIX posix = context.runtime.getPosix();
@@ -458,14 +459,26 @@ private RubyString getCorrectKey(IRubyObject key, ThreadContext context) {
return actualKey;
}

private IRubyObject normalizeEnvString(IRubyObject str) {
if (str instanceof RubyString) {
Encoding enc = getRuntime().getEncodingService().getLocaleEncoding();
RubyString newStr = getRuntime().newString(new ByteList(str.toString().getBytes(), enc));
newStr.setFrozen(true);
return newStr;
private IRubyObject normalizeEnvString(ThreadContext context, IRubyObject key, IRubyObject value) {
if (value instanceof RubyString) {
Ruby runtime = context.runtime;
RubyString valueStr = (RubyString) value;

// Ensure PATH is encoded like filesystem
if (Platform.IS_WINDOWS ?
key.toString().equalsIgnoreCase("PATH") :
key.toString().equals("PATH")) {
Encoding enc = runtime.getEncodingService().getFileSystemEncoding();
valueStr = EncodingUtils.strConvEnc(context, valueStr, valueStr.getEncoding(), enc);
} else {
valueStr = RubyString.newString(runtime, valueStr.toString(), runtime.getEncodingService().getLocaleEncoding());
}

valueStr.setFrozen(true);

return valueStr;
}
return str;
return value;
}
}

12 changes: 6 additions & 6 deletions core/src/main/java/org/jruby/runtime/Helpers.java
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@
import static org.jruby.util.StringSupport.EMPTY_STRING_ARRAY;

import org.jruby.util.JavaNameMangler;
import org.jruby.util.io.EncodingUtils;

/**
* Helper methods which are called by the compiler. Note: These will show no consumers, but
@@ -2645,15 +2646,14 @@ public static String decodeByteList(Ruby runtime, ByteList value) {
Charset charset = runtime.getEncodingService().charsetForEncoding(encoding);

if (charset == null) {
try {
return new String(unsafeBytes, begin, length, encoding.toString());
} catch (UnsupportedEncodingException uee) {
return value.toString();
}
// No JDK Charset available for this encoding; convert to UTF-16 ourselves.
Encoding utf16 = EncodingUtils.getUTF16ForPlatform();

return EncodingUtils.strConvEnc(runtime.getCurrentContext(), value, value.getEncoding(), utf16).toString();
}

return RubyEncoding.decode(unsafeBytes, begin, length, charset);
}
}

/**
* Convert a ByteList into a Java String by using its Encoding's Charset. If
22 changes: 15 additions & 7 deletions core/src/main/java/org/jruby/util/OSEnvironment.java
Original file line number Diff line number Diff line change
@@ -89,15 +89,15 @@ public Map<RubyString, RubyString> getSystemPropertiesMap(Ruby runtime) {
private static Map<RubyString, RubyString> asMapOfRubyStrings(final Ruby runtime, final Map<?, ?> map) {
@SuppressWarnings("unchecked")
final Map<RubyString, RubyString> rubyMap = new HashMap(map.size() + 2);
Encoding encoding = runtime.getEncodingService().getLocaleEncoding();
Encoding keyEncoding = runtime.getEncodingService().getLocaleEncoding();

// On Windows, map doesn't have corresponding keys for these
if (Platform.IS_WINDOWS) {
// these may be null when in a restricted environment (JRUBY-6514)
String home = SafePropertyAccessor.getProperty("user.home");
String user = SafePropertyAccessor.getProperty("user.name");
putRubyKeyValuePair(runtime, rubyMap, "HOME", home == null ? "/" : home, encoding);
putRubyKeyValuePair(runtime, rubyMap, "USER", user == null ? "" : user, encoding);
putRubyKeyValuePair(runtime, rubyMap, "HOME", keyEncoding, home == null ? "/" : home, keyEncoding);
putRubyKeyValuePair(runtime, rubyMap, "USER", keyEncoding, user == null ? "" : user, keyEncoding);
}

for (Map.Entry<?, ?> entry : map.entrySet()) {
@@ -111,17 +111,25 @@ private static Map<RubyString, RubyString> asMapOfRubyStrings(final Ruby runtime
val = entry.getValue();
if ( ! (val instanceof String) ) continue; // Java devs can stuff non-string objects into env

putRubyKeyValuePair(runtime, rubyMap, key, (String) val, encoding);
// Ensure PATH is encoded like filesystem
Encoding valueEncoding = keyEncoding;
if ( org.jruby.platform.Platform.IS_WINDOWS ?
key.toString().equalsIgnoreCase("PATH") :
key.toString().equals("PATH") ) {
valueEncoding = runtime.getEncodingService().getFileSystemEncoding();
}

putRubyKeyValuePair(runtime, rubyMap, key, keyEncoding, (String) val, valueEncoding);
}

return rubyMap;
}

private static void putRubyKeyValuePair(Ruby runtime,
final Map<RubyString, RubyString> map,
String key, String value, Encoding encoding) {
ByteList keyBytes = new ByteList(key.getBytes(), encoding);
ByteList valueBytes = new ByteList(value.getBytes(), encoding);
String key, Encoding keyEncoding, String value, Encoding valueEncoding) {
ByteList keyBytes = RubyString.encodeBytelist(key, keyEncoding);
ByteList valueBytes = RubyString.encodeBytelist(value, valueEncoding);

RubyString keyString = runtime.newString(keyBytes);
RubyString valueString = runtime.newString(valueBytes);
17 changes: 11 additions & 6 deletions core/src/main/java/org/jruby/util/io/EncodingUtils.java
Original file line number Diff line number Diff line change
@@ -1268,12 +1268,7 @@ public static void transcodeLoop(ThreadContext context, byte[] inBytes, Ptr inPo
public static ByteList transcodeString(String string, Encoding toEncoding, int ecflags) {
Encoding encoding;

// This may be inefficient if we aren't matching endianness right
if (Platform.BYTE_ORDER == Platform.LITTLE_ENDIAN) {
encoding = UTF16LEEncoding.INSTANCE;
} else {
encoding = UTF16BEEncoding.INSTANCE;
}
encoding = getUTF16ForPlatform();

EConv ec = TranscoderDB.open(encoding.getName(), toEncoding.getName(), ecflags);

@@ -1298,6 +1293,16 @@ public static ByteList transcodeString(String string, Encoding toEncoding, int e
return destination;
}

public static Encoding getUTF16ForPlatform() {
Encoding encoding;// This may be inefficient if we aren't matching endianness right
if (Platform.BYTE_ORDER == Platform.LITTLE_ENDIAN) {
encoding = UTF16LEEncoding.INSTANCE;
} else {
encoding = UTF16BEEncoding.INSTANCE;
}
return encoding;
}

/**
* Perform the inner transcoding loop.
*
3 changes: 2 additions & 1 deletion core/src/main/ruby/jruby/kernel.rb
Original file line number Diff line number Diff line change
@@ -32,4 +32,5 @@
load 'jruby/kernel/time.rb'
load 'jruby/kernel/gc.rb'
load 'jruby/kernel/range.rb'
load 'jruby/kernel/load_error.rb'
load 'jruby/kernel/load_error.rb'
load 'jruby/kernel/file.rb'
159 changes: 159 additions & 0 deletions core/src/main/ruby/jruby/kernel/file.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Windows symlink support borrowed from djberg96/win32-file and ffi-win32-extensions

if org.jruby.platform.Platform::IS_WINDOWS

module JRuby
module Windows
module File
module Constants
FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
INVALID_HANDLE_VALUE = (1 << FFI::Platform::ADDRESS_SIZE) - 1
INVALID_FILE_ATTRIBUTES = (1 << FFI::Platform::ADDRESS_SIZE) - 1
IO_REPARSE_TAG_SYMLINK = 0xA000000C
end

module Functions
extend FFI::Library
ffi_lib :kernel32

typedef :ulong, :dword
typedef :uintptr_t, :handle
typedef :pointer, :ptr

def self.attach_pfunc(*args)
attach_function(*args)
private args[0]
end

attach_pfunc :CloseHandle, [:handle], :bool
attach_pfunc :FindFirstFileW, [:buffer_in, :pointer], :handle
attach_pfunc :CreateSymbolicLinkW, [:buffer_in, :buffer_in, :dword], :bool
attach_pfunc :GetFileAttributesW, [:buffer_in], :dword

attach_pfunc :CreateFileW, [:buffer_in, :dword, :dword, :pointer, :dword, :dword, :handle], :handle
attach_pfunc :GetDiskFreeSpaceW, [:buffer_in, :pointer, :pointer, :pointer, :pointer], :bool
attach_pfunc :GetDriveTypeW, [:buffer_in], :uint
attach_pfunc :GetFileType, [:handle], :dword
attach_pfunc :GetFinalPathNameByHandleW, [:handle, :buffer_out, :dword, :dword], :dword
attach_pfunc :GetShortPathNameW, [:buffer_in, :buffer_out, :dword], :dword
attach_pfunc :GetLongPathNameW, [:buffer_in, :buffer_out, :dword], :dword
attach_pfunc :QueryDosDeviceA, [:string, :buffer_out, :dword], :dword
attach_pfunc :SetFileTime, [:handle, :ptr, :ptr, :ptr], :bool
attach_pfunc :SystemTimeToFileTime, [:ptr, :ptr], :bool

ffi_lib :shlwapi

attach_pfunc :PathFindExtensionW, [:buffer_in], :pointer
attach_pfunc :PathIsRootW, [:buffer_in], :bool
attach_pfunc :PathStripPathW, [:pointer], :void
attach_pfunc :PathRemoveBackslashW, [:buffer_in], :string
attach_pfunc :PathRemoveFileSpecW, [:pointer], :bool
attach_pfunc :PathRemoveExtensionW, [:buffer_in], :void
attach_pfunc :PathStripToRootW, [:buffer_in], :bool
end

module Structs
class FILETIME < FFI::Struct
layout(:dwLowDateTime, :ulong, :dwHighDateTime, :ulong)
end

class WIN32_FIND_DATA < FFI::Struct
layout(
:dwFileAttributes, :ulong,
:ftCreationTime, FILETIME,
:ftLastAccessTime, FILETIME,
:ftLastWriteTime, FILETIME,
:nFileSizeHigh, :ulong,
:nFileSizeLow, :ulong,
:dwReserved0, :ulong,
:dwReserved1, :ulong,
:cFileName, [:uint8, 260*2],
:cAlternateFileName, [:uint8, 14*2]
)
end
end
end
end
end

class File
include Windows::File::Constants
include Windows::File::Structs
extend Windows::File::Functions

# Creates a symbolic link called +new_name+ for the file or directory
# +old_name+.
#
# This method requires Windows Vista or later to work. Otherwise, it
# returns nil as per MRI.
#
def self.symlink(target, link)
target = string_check(target)
link = string_check(link)

flags = File.directory?(target) ? 1 : 0

wlink = link.wincode
wtarget = target.wincode

unless CreateSymbolicLinkW(wlink, wtarget, flags)
raise SystemCallError.new('CreateSymbolicLink', FFI.errno)
end

0 # Comply with spec
end

# Returns whether or not +file+ is a symlink.
#
def self.symlink?(file)
return false unless File.exist?(file)

bool = false
wfile = string_check(file).wincode

attrib = GetFileAttributesW(wfile)

if attrib == INVALID_FILE_ATTRIBUTES
raise SystemCallError.new('GetFileAttributes', FFI.errno)
end

if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0
begin
find_data = WIN32_FIND_DATA.new
handle = FindFirstFileW(wfile, find_data)

if handle == INVALID_HANDLE_VALUE
raise SystemCallError.new('FindFirstFile', FFI.errno)
end

if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
bool = true
end
ensure
CloseHandle(handle)
end
end

bool
end

private

# Simulate Ruby's string checking
def self.string_check(arg)
return arg if arg.is_a?(String)
return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str
return arg.to_path if arg.respond_to?(:to_path)
raise TypeError
end
end

class String
# Convenience method for converting strings to UTF-16LE for wide character
# functions that require it.
#
def wincode
(self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
end
end
end
Original file line number Diff line number Diff line change
@@ -44,17 +44,10 @@
exclude_tests.rb: |
failures = { KernelTest: [:test_silence_stream,
:test_quietly],
InflectorTest: [:test_titleize_mixture_to_title_case_14],
LoadPathsTest: [:test_uniq_load_paths],
LoggerTest: [:test_buffer_multibyte],
MultibyteCharsExtrasTest: [:test_titleize_should_be_unicode_aware,
:test_titleize_should_not_affect_characters_that_do_not_case_fold],
TransliterateTest: [:test_transliterate_should_allow_a_custom_replacement_char,
:test_transliterate_should_approximate_ascii,
:test_transliterate_should_work_with_custom_i18n_rules_and_uncomposed_utf8],
StringInflectionsTest: [:test_string_parameterized_no_separator,
:test_string_parameterized_normal,
:test_string_parameterized_underscore],
TimeZoneTest: :test_map_srednekolymsk_to_tzinfo }
11 changes: 3 additions & 8 deletions mx.jruby/mx_jruby.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import mx
import os
from os.path import join, exists
import subprocess
import shutil

@@ -84,9 +83,9 @@ def build(self):

mx.run_mx(['maven-install'], suite=truffle)

open(join(rubyDir, 'VERSION'), 'w').write('graal-vm\n')
open(os.path.join(rubyDir, 'VERSION'), 'w').write('graal-vm\n')

# Build jruby-truffle and
# Build jruby-truffle

mx.run(['find', '.'], nonZeroIsFatal=False, cwd=rubyDir)
mx.run_maven(['--version'], nonZeroIsFatal=False, cwd=rubyDir)
@@ -100,14 +99,10 @@ def build(self):
mx.run_maven(['-Pcomplete', '-DskipTests', '-Dtruffle.version=' + truffle_commit], cwd=rubyDir)
mx.run(['zip', '-d', 'maven/jruby-complete/target/jruby-complete-graal-vm.jar', 'META-INF/jruby.home/lib/*'], cwd=rubyDir)
mx.run(['bin/jruby', 'bin/gem', 'install', 'bundler', '-v', '1.10.6'], cwd=rubyDir)
# shutil.rmtree(os.path.join(_suite.dir, "lib", "target"), True)
# shutil.rmtree(os.path.join(_suite.dir, 'lib', 'lib', 'jni'), True)
# shutil.copytree(os.path.join(_suite.dir, 'lib', 'jni'), os.path.join(_suite.dir, 'lib', 'lib', 'jni'))
# shutil.rmtree(os.path.join(_suite.dir, 'lib', 'jni'), True)
mx.log('...finished build of {}'.format(self.subject))

def clean(self, forBuild=False):
if forBuild:
return
rubyDir = _suite.dir
mx.run_maven(['clean'], nonZeroIsFatal=False, cwd=rubyDir)

Loading

0 comments on commit 8432aab

Please sign in to comment.