From 798620db716c938c617d305d6a6ab35c1e6988c2 Mon Sep 17 00:00:00 2001 From: Andy Pfister Date: Wed, 8 Jan 2025 17:14:38 +0100 Subject: [PATCH] Fix FreeTDS utility wrappers --- .github/workflows/ci.yml | 92 +++++++++++++++++++++++++++++++++++-- CHANGELOG.md | 1 + Rakefile | 12 ++++- ext/tiny_tds/extconf.rb | 5 +- lib/tiny_tds/bin.rb | 15 +----- lib/tiny_tds/gem.rb | 8 +--- test/bin/install-freetds.sh | 6 +-- test/gem_test.rb | 73 ----------------------------- 8 files changed, 107 insertions(+), 105 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb29f398..ec714572 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,10 +39,10 @@ jobs: uses: actions/cache@v4 with: path: ports - key: cross-compiled-v8-${{ matrix.platform }}-${{ hashFiles('**/.ports_versions') }} + key: cross-compiled-v9-${{ matrix.platform }}-${{ hashFiles('**/.ports_versions') }} restore-keys: | - cross-compiled-v8-${{ matrix.platform }}-${{ hashFiles('**/.ports_versions') }} - cross-compiled-v8-${{ matrix.platform }}- + cross-compiled-v9-${{ matrix.platform }}-${{ hashFiles('**/.ports_versions') }} + cross-compiled-v9-${{ matrix.platform }}- - name: Build gem shell: bash @@ -94,6 +94,18 @@ jobs: ruby -e "require 'tiny_tds'; puts TinyTds::Gem.root_path" exit $LASTEXITCODE + - name: Test if tsql wrapper works + shell: pwsh + run: | + tsql-ttds -C + exit $LASTEXITCODE + + - name: Test if defncopy wrapper works + shell: pwsh + run: | + defncopy-ttds -v + exit $LASTEXITCODE + test-windows-mingw: needs: - cross-compile @@ -207,6 +219,18 @@ jobs: ruby -e "require 'tiny_tds'; puts TinyTds::Gem.root_path" exit $LASTEXITCODE + - name: Test if tsql wrapper works + shell: pwsh + run: | + tsql-ttds -C + exit $LASTEXITCODE + + - name: Test if defncopy wrapper works + shell: pwsh + run: | + defncopy-ttds -v + exit $LASTEXITCODE + test-windows-ucrt: needs: - cross-compile @@ -317,6 +341,18 @@ jobs: ruby -e "require 'tiny_tds'; puts TinyTds::Gem.root_path" exit $LASTEXITCODE + - name: Test if tsql wrapper works + shell: pwsh + run: | + tsql-ttds -C + exit $LASTEXITCODE + + - name: Test if defncopy wrapper works + shell: pwsh + run: | + defncopy-ttds -v + exit $LASTEXITCODE + install-linux: needs: - cross-compile @@ -372,7 +408,9 @@ jobs: gem update --system 3.3.22 && ${{ matrix.bootstrap }} gem install --no-document ./gems/tiny_tds-$(cat VERSION)-${{ matrix.platform }}.gem && - ruby -e \"require 'tiny_tds'; puts TinyTds::Gem.root_path\" + ruby -e \"require 'tiny_tds'; puts TinyTds::Gem.root_path\" && + tsql-ttds -C && + defncopy-ttds -v " test-linux: @@ -449,6 +487,52 @@ jobs: paths: "test/reports/TEST-*.xml" if: always() + install-linux-native: + strategy: + fail-fast: false + matrix: + ruby-version: + - "2.7" + - "3.0" + - "3.1" + - "3.2" + - "3.3" + - "3.4" + + name: install-linux-native + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Install FreeTDS + shell: bash + run: ./test/bin/install-freetds.sh + + - name: Build gem + shell: bash + run: gem build tiny_tds.gemspec + + - name: Install gem + shell: bash + run: gem install "tiny_tds-$(cat VERSION).gem" + + - name: Test if TinyTDS loads + shell: bash + run: ruby -e "require 'tiny_tds'; puts TinyTds::Gem.root_path" + + - name: Test if tsql wrapper works + shell: bash + run: tsql-ttds -C + + - name: Test if defncopy wrapper works + shell: bash + run: defncopy-ttds -v + install_macos: strategy: fail-fast: false diff --git a/CHANGELOG.md b/CHANGELOG.md index c79b64f8..ffe8e6b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Reduce number of files shipped with precompiled Windows gem * Provide precompiled gem for Linux (GNU + MUSL / 64-bit x86 + ARM) +* Fix wrappers for `tsql` and `defncopy` utility. ## 3.1.0 diff --git a/Rakefile b/Rakefile index e4bef2f7..ec6da503 100644 --- a/Rakefile +++ b/Rakefile @@ -40,9 +40,17 @@ Rake::ExtensionTask.new('tiny_tds', SPEC) do |ext| spec.metadata.delete('msys2_mingw_dependencies') if spec.platform.to_s =~ /mingw/ - spec.files << "ports/#{spec.platform.to_s}/bin/libsybdb-5.dll" + spec.files += [ + "ports/#{spec.platform.to_s}/bin/libsybdb-5.dll", + "ports/#{spec.platform.to_s}/bin/defncopy.exe", + "ports/#{spec.platform.to_s}/bin/tsql.exe" + ] elsif spec.platform.to_s =~ /linux/ - spec.files << "ports/#{spec.platform.to_s}/lib/libsybdb.so.5" + spec.files += [ + "ports/#{spec.platform.to_s}/lib/libsybdb.so.5", + "ports/#{spec.platform.to_s}/bin/defncopy", + "ports/#{spec.platform.to_s}/bin/tsql" + ] end end diff --git a/ext/tiny_tds/extconf.rb b/ext/tiny_tds/extconf.rb index 152ef052..47f6630c 100644 --- a/ext/tiny_tds/extconf.rb +++ b/ext/tiny_tds/extconf.rb @@ -105,8 +105,9 @@ def configure_defaults recipe.configure_options << "--enable-sspi" end - recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib" - recipe.configure_options << "LIBS=-liconv -lssl -lcrypto #{"-lwsock32 -lgdi32 -lws2_32 -lcrypt32" if MiniPortile.windows?} #{"-ldl -lpthread" if MiniPortile.linux?}" + # pass an additional runtime path to the linker so defncopy and tsql can find our shared sybdb + recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib #{"-Wl,-rpath='$$ORIGIN/../lib'" if MiniPortile.linux?}" + recipe.configure_options << "LIBS=-liconv -lssl -lcrypto #{"-lwsock32 -lgdi32 -lws2_32 -lcrypt32" if MiniPortile.windows?} #{"-ldl -lpthread" if MiniPortile.linux?}" recipe.configure_options << "CPPFLAGS=-I#{openssl_recipe.path}/include" recipe.configure_options << "OPENSSL_CFLAGS=-L#{openssl_recipe.path}/lib" diff --git a/lib/tiny_tds/bin.rb b/lib/tiny_tds/bin.rb index 832692a3..87cee11a 100644 --- a/lib/tiny_tds/bin.rb +++ b/lib/tiny_tds/bin.rb @@ -81,24 +81,11 @@ def which exe = File.expand_path File.join(path, "#{name}#{ext}"), @root next if exe == @binstub next unless File.executable?(exe) - next unless binary?(exe) + return exe end end nil end - - # Implementation directly copied from ptools. - # https://github.com/djberg96/ptools - # https://opensource.org/licenses/Artistic-2.0 - # - def binary?(file) - bytes = File.stat(file).blksize - return false unless bytes - bytes = 4096 if bytes > 4096 - s = (File.read(file, bytes) || '') - s = s.encode('US-ASCII', undef: :replace).split(//) - ((s.size - s.grep(' '..'~').size) / s.size.to_f) > 0.30 - end end end diff --git a/lib/tiny_tds/gem.rb b/lib/tiny_tds/gem.rb index a52f047d..55be78b4 100644 --- a/lib/tiny_tds/gem.rb +++ b/lib/tiny_tds/gem.rb @@ -12,15 +12,11 @@ def ports_root_path end def ports_bin_paths - Dir.glob(File.join(ports_root_path,ports_host,'**','bin')) + Dir.glob(File.join(ports_root_path, '**', 'bin')) end def ports_lib_paths - Dir.glob(File.join(ports_root_path,ports_host,'**','lib')) - end - - def ports_host - RbConfig::CONFIG["arch"] + Dir.glob(File.join(ports_root_path, '**', 'lib')) end end end diff --git a/test/bin/install-freetds.sh b/test/bin/install-freetds.sh index d4ba3955..8c1f0eac 100755 --- a/test/bin/install-freetds.sh +++ b/test/bin/install-freetds.sh @@ -10,11 +10,9 @@ fi wget http://www.freetds.org/files/stable/freetds-$FREETDS_VERSION.tar.gz tar -xzf freetds-$FREETDS_VERSION.tar.gz cd freetds-$FREETDS_VERSION -./configure --prefix=/opt/local \ - --with-openssl=/opt/local \ - --with-tdsver=7.3 +./configure make -make install +sudo make install cd .. rm -rf freetds-$FREETDS_VERSION rm freetds-$FREETDS_VERSION.tar.gz diff --git a/test/gem_test.rb b/test/gem_test.rb index 0412a88a..eea45623 100644 --- a/test/gem_test.rb +++ b/test/gem_test.rb @@ -98,79 +98,6 @@ class GemTest < Minitest::Spec end end end - - describe '#ports_lib_paths' do - let(:ports_lib_paths) { TinyTds::Gem.ports_lib_paths } - - describe 'when the ports directories exist' do - let(:fake_lib_paths) do - ports_host_root = File.join(gem_root, 'ports', 'fake-host-with-dirs') - [ - File.join('a','lib'), - File.join('a','inner','lib'), - File.join('b','lib') - ].map do |p| - File.join(ports_host_root, p) - end - end - - before do - RbConfig::CONFIG['arch'] = 'fake-host-with-dirs' - fake_lib_paths.each do |path| - FileUtils.mkdir_p(path) - end - end - - after do - FileUtils.remove_entry_secure( - File.join(gem_root, 'ports', 'fake-host-with-dirs'), true - ) - end - - it 'should return all the lib directories' do - _(ports_lib_paths.sort).must_equal fake_lib_paths.sort - end - - it 'should return all the lib directories regardless of cwd' do - Dir.chdir '/' - _(ports_lib_paths.sort).must_equal fake_lib_paths.sort - end - end - - describe 'when the ports directories are missing' do - before do - RbConfig::CONFIG['arch'] = 'fake-host-without-dirs' - end - - - it 'should return no directories' do - _(ports_lib_paths).must_be_empty - end - - it 'should return no directories regardless of cwd' do - Dir.chdir '/' - _(ports_lib_paths).must_be_empty - end - end - end - - describe '#ports_host' do - { - 'x64-mingw-ucrt' => 'x64-mingw-ucrt', - 'x64-mingw32' => 'x64-mingw32', - 'x86_64-linux' => 'x86_64-linux', - }.each do |host,expected| - describe "on a #{host} architecture" do - before do - RbConfig::CONFIG['arch'] = host - end - - it "should return a #{expected} ports host" do - _(TinyTds::Gem.ports_host).must_equal expected - end - end - end - end end end