pg 1.6.0.rc1-x86-mingw32 → 1.6.0-x86-mingw32

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.
@@ -7,8 +7,24 @@ if defined?(PG::CancelConnection)
7
7
  class PG::CancelConnection
8
8
  include PG::Connection::Pollable
9
9
 
10
- # The timeout used by #cancel and async_cancel to establish the cancel connection.
11
- attr_accessor :async_connect_timeout
10
+ alias c_initialize initialize
11
+
12
+ def initialize(conn)
13
+ c_initialize(conn)
14
+
15
+ # A cancel connection is always to one destination server only.
16
+ # Prepare conninfo_hash with just enough information to allow a shared polling_loop.
17
+ @host = conn.host
18
+ @hostaddr = conn.hostaddr
19
+ @port = conn.port
20
+
21
+ @conninfo_hash = {
22
+ host: @host,
23
+ hostaddr: @hostaddr,
24
+ port: @port.to_s,
25
+ connect_timeout: conn.conninfo_hash[:connect_timeout],
26
+ }
27
+ end
12
28
 
13
29
  # call-seq:
14
30
  # conn.cancel
@@ -23,8 +39,15 @@ if defined?(PG::CancelConnection)
23
39
  #
24
40
  def cancel
25
41
  start
26
- polling_loop(:poll, async_connect_timeout)
42
+ polling_loop(:poll)
27
43
  end
28
44
  alias async_cancel cancel
45
+
46
+ # These private methods are there to allow a shared polling_loop.
47
+ private
48
+ attr_reader :host
49
+ attr_reader :hostaddr
50
+ attr_reader :port
51
+ attr_reader :conninfo_hash
29
52
  end
30
53
  end
data/lib/pg/coder.rb CHANGED
@@ -76,12 +76,13 @@ module PG
76
76
  elements_type: elements_type,
77
77
  needs_quotation: needs_quotation?,
78
78
  delimiter: delimiter,
79
+ dimensions: dimensions,
79
80
  }
80
81
  end
81
82
 
82
83
  def inspect
83
84
  str = super
84
- str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation"
85
+ str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation#{dimensions && " #{dimensions} dimensions"}"
85
86
  str
86
87
  end
87
88
  end
data/lib/pg/connection.rb CHANGED
@@ -625,7 +625,6 @@ class PG::Connection
625
625
  # On older client library a pure ruby implementation is used.
626
626
  def cancel
627
627
  cancon = PG::CancelConnection.new(self)
628
- cancon.async_connect_timeout = conninfo_hash[:connect_timeout]
629
628
  cancon.async_cancel
630
629
  rescue PG::Error => err
631
630
  err.to_s
@@ -674,20 +673,35 @@ class PG::Connection
674
673
  alias async_cancel cancel
675
674
 
676
675
  module Pollable
677
- # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
678
- private def polling_loop(poll_meth, connect_timeout)
676
+ # Track the progress of the connection, waiting for the socket to become readable/writable before polling it.
677
+ #
678
+ # Connecting to multiple hosts is done like so:
679
+ # - All hosts are passed to PG::Connection.connect_start
680
+ # - As soon as the host is tried to connect the related host is removed from the hosts list
681
+ # - When the polling status changes to `PG::PGRES_POLLING_OK` the connection is returned and ready to use.
682
+ # - When the polling status changes to `PG::PGRES_POLLING_FAILED` connecting is aborted and a PG::ConnectionBad is raised with details to all connection attepts.
683
+ # - When a timeout occurs, connecting is restarted with the remaining hosts.
684
+ #
685
+ # The downside is that this connects only once to hosts which are listed twice when they timeout.
686
+ private def polling_loop(poll_meth)
687
+ connect_timeout = conninfo_hash[:connect_timeout]
679
688
  if (timeo = connect_timeout.to_i) && timeo > 0
680
- host_count = conninfo_hash[:host].to_s.count(",") + 1
689
+ host_count = (conninfo_hash[:hostaddr].to_s.empty? ? conninfo_hash[:host] : conninfo_hash[:hostaddr]).to_s.count(",") + 1
681
690
  stop_time = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
682
691
  end
683
-
692
+ iopts = conninfo_hash.compact
693
+ connection_errors = []
684
694
  poll_status = PG::PGRES_POLLING_WRITING
695
+
685
696
  until poll_status == PG::PGRES_POLLING_OK ||
686
697
  poll_status == PG::PGRES_POLLING_FAILED
687
698
 
688
699
  # Set single timeout to parameter "connect_timeout" but
689
700
  # don't exceed total connection time of number-of-hosts * connect_timeout.
690
701
  timeout = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
702
+
703
+ hostcnt = remove_current_host(iopts)
704
+
691
705
  event = if !timeout || timeout >= 0
692
706
  # If the socket needs to read, wait 'til it becomes readable to poll again
693
707
  case poll_status
@@ -710,17 +724,21 @@ class PG::Connection
710
724
  end
711
725
  end
712
726
  end
727
+
713
728
  # connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
714
729
  # connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
715
730
  unless event
716
- if self.class.send(:host_is_named_pipe?, host)
717
- connhost = "on socket \"#{host}\""
718
- elsif respond_to?(:hostaddr)
719
- connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
731
+ connection_errors << (error_message + "timeout expired")
732
+ if hostcnt > 0
733
+ reset_start2(self.class.parse_connect_args(iopts))
734
+ # Restart polling with waiting for writable.
735
+ # Otherwise "not connected" error is raised on Windows.
736
+ poll_status = PG::PGRES_POLLING_WRITING
737
+ next
720
738
  else
721
- connhost = "at \"#{host}\", port #{port}"
739
+ finish
740
+ raise PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self)
722
741
  end
723
- raise PG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", connection: self)
724
742
  end
725
743
 
726
744
  # Check to see if it's finished or failed yet
@@ -730,16 +748,51 @@ class PG::Connection
730
748
  unless status == PG::CONNECTION_OK
731
749
  msg = error_message
732
750
  finish
733
- raise PG::ConnectionBad.new(msg, connection: self)
751
+ raise PG::ConnectionBad.new(connection_errors.map{|e| e + "\n" }.join.b + msg, connection: self)
734
752
  end
735
753
  end
754
+
755
+ # Remove the host to which the connection is currently established from the option hash.
756
+ # Affected options are:
757
+ # - :host
758
+ # - :hostaddr
759
+ # - :port
760
+ #
761
+ # Return the number of remaining hosts.
762
+ private def remove_current_host(iopts)
763
+ ihosts = iopts[:host]&.split(",", -1)
764
+ ihostaddrs = iopts[:hostaddr]&.split(",", -1)
765
+ iports = iopts[:port]&.split(",", -1)
766
+ iports = iports * (ihosts || ihostaddrs || [1]).size if iports&.size == 1
767
+
768
+ idx = (ihosts || ihostaddrs || iports).index.with_index do |_, i|
769
+ (ihosts ? ihosts[i] == host : true) &&
770
+ (ihostaddrs && respond_to?(:hostaddr, true) ? ihostaddrs[i] == hostaddr : true) &&
771
+ (iports ? iports[i].to_i == port : true)
772
+ end
773
+
774
+ if idx
775
+ ihosts&.delete_at(idx)
776
+ ihostaddrs&.delete_at(idx)
777
+ iports&.delete_at(idx)
778
+
779
+ iopts.merge!(
780
+ host: ihosts.join(",")) if ihosts
781
+ iopts.merge!(
782
+ hostaddr: ihostaddrs.join(",")) if ihostaddrs
783
+ iopts.merge!(
784
+ port: iports.join(",")) if iports
785
+ end
786
+
787
+ (ihosts || ihostaddrs || iports).size
788
+ end
736
789
  end
737
790
 
738
791
  include Pollable
739
792
 
740
793
  private def async_connect_or_reset(poll_meth)
741
794
  # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
742
- polling_loop(poll_meth, conninfo_hash[:connect_timeout])
795
+ polling_loop(poll_meth)
743
796
 
744
797
  # Set connection to nonblocking to handle all blocking states in ruby.
745
798
  # That way a fiber scheduler is able to handle IO requests.
@@ -755,7 +808,7 @@ class PG::Connection
755
808
  # PG::Connection.new(connection_string) -> conn
756
809
  # PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
757
810
  #
758
- # Create a connection to the specified server.
811
+ # === Create a connection to the specified server.
759
812
  #
760
813
  # +connection_hash+ must be a ruby Hash with connection parameters.
761
814
  # See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
@@ -779,7 +832,13 @@ class PG::Connection
779
832
  # [+password+]
780
833
  # login password
781
834
  #
782
- # Examples:
835
+ #
836
+ # If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
837
+ # connection will have its +client_encoding+ set accordingly.
838
+ #
839
+ # Raises a PG::Error if the connection fails.
840
+ #
841
+ # === Examples:
783
842
  #
784
843
  # # Connect using all defaults
785
844
  # PG::Connection.new
@@ -796,10 +855,18 @@ class PG::Connection
796
855
  # # As an URI
797
856
  # PG::Connection.new( "postgresql://user:pass@pgsql.example.com:5432/testdb?sslmode=require" )
798
857
  #
799
- # If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
800
- # connection will have its +client_encoding+ set accordingly.
858
+ # === Specifying Multiple Hosts
859
+ #
860
+ # It is possible to specify multiple hosts to connect to, so that they are tried in the given order or optionally in random order.
861
+ # In the Keyword/Value format, the host, hostaddr, and port options accept comma-separated lists of values.
862
+ # The {details to libpq}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS] describe how it works, but there are two small differences how ruby-pg handles multiple hosts:
863
+ # - All hosts are resolved before the first connection is tried.
864
+ # This means that when +load_balance_hosts+ is set to +random+, then all resolved addresses are tried randomly in one level.
865
+ # When a host resolves to more than one address, it is therefore tried more often than a host that has only one address.
866
+ # - When a timeout occurs due to the value of +connect_timeout+, then the given +host+, +hostaddr+ and +port+ combination is not tried a second time, even if it's specified several times.
867
+ # It's still possible to do load balancing with +load_balance_hosts+ set to +random+ and to increase the number of connections a node gets, when the hostname is provided multiple times in the host string.
868
+ # This is because in non-timeout cases the host is tried multiple times.
801
869
  #
802
- # Raises a PG::Error if the connection fails.
803
870
  def new(*args)
804
871
  conn = connect_to_hosts(*args)
805
872
 
@@ -857,7 +924,7 @@ class PG::Connection
857
924
  iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
858
925
  iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
859
926
 
860
- if PG::BUNDLED_LIBPQ_WITH_UNIXSOCKET && iopts[:host].to_s.empty?
927
+ if PG::BUNDLED_LIBPQ_WITH_UNIXSOCKET && iopts[:host].to_s.empty? && iopts[:hostaddr].to_s.empty?
861
928
  # Many distors patch the hardcoded default UnixSocket path in libpq to /var/run/postgresql instead of /tmp .
862
929
  # We simply try them all.
863
930
  iopts[:host] = "/var/run/postgresql" + # Ubuntu, Debian, Fedora, Opensuse
data/lib/pg/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module PG
2
2
  # Library version
3
- VERSION = '1.6.0.rc1'
3
+ VERSION = '1.6.0'
4
4
  end
@@ -0,0 +1,9 @@
1
+ FROM yugabytedb/yugabyte:2024.1.0.0-b129
2
+
3
+ WORKDIR /app
4
+
5
+ RUN yugabyted cert generate_server_certs --hostnames=127.0.0.1 --base_dir=.
6
+
7
+ ENTRYPOINT ["yugabyted"]
8
+ CMD ["start", "--background", "false", "--ui", "false", "--tserver_flags", "use_client_to_server_encryption=true,cert_node_filename=127.0.0.1,certs_dir=/app/generated_certs/127.0.0.1"]
9
+ VOLUME /app
@@ -0,0 +1,28 @@
1
+ services:
2
+ yb:
3
+ build: .
4
+ container_name: yb
5
+ ports:
6
+ - "127.0.0.1:5433:5433"
7
+ volumes:
8
+ - certs:/app/generated_certs
9
+ healthcheck:
10
+ test: 'ysqlsh -h $$(hostname) -c \\conninfo || exit 1;'
11
+ interval: 2s
12
+ timeout: 30s
13
+ retries: 20
14
+ start_period: 10s
15
+
16
+ pg:
17
+ image: ruby:3.0
18
+ working_dir: /app
19
+ volumes:
20
+ - .:/app
21
+ - certs:/generated_certs
22
+ command: bash -c "gem inst pg-*.gem && ruby pg-test.rb"
23
+ depends_on:
24
+ yb:
25
+ condition: service_healthy
26
+
27
+ volumes:
28
+ certs:
@@ -0,0 +1,45 @@
1
+ require 'pg'
2
+
3
+ conn = PG.connect(
4
+ host: 'yb',
5
+ port: 5433,
6
+ user: 'yugabyte',
7
+ dbname: 'yugabyte',
8
+ sslmode: 'require',
9
+ sslrootcert: 'app/generated_certs/127.0.0.1/ca.crt',
10
+ sslcert: 'app/generated_certs/127.0.0.1/node.127.0.0.1.crt',
11
+ sslkey: 'app/generated_certs/127.0.0.1/node.127.0.0.1.key'
12
+ )
13
+
14
+ $stdout.sync = true
15
+ # fd = File.open("pg_trace.log", "a+")
16
+ # conn.trace(fd)
17
+
18
+ begin
19
+ # Validate connection is working
20
+ res = conn.exec("SELECT version();")
21
+ res.each_row do |row|
22
+ puts "You are connected to: #{row[0]}"
23
+ end
24
+ # 53*511
25
+ # 53*767
26
+ # 53*1023
27
+ # 53*1279
28
+ # 7*1817
29
+ # 11*1487
30
+ # 13*1363
31
+ # 16*1211
32
+ # 18*1128
33
+ # 22*1984
34
+ # 27*1723
35
+
36
+ (22..53).each do |m|
37
+ (1..2048).each do |l|
38
+ hanging_query = "SELECT lpad(''::text, #{m}, '0') FROM generate_series(1, #{l});"
39
+ puts "Executing hanging query: #{hanging_query}"
40
+ conn.exec(hanging_query)
41
+ end
42
+ end
43
+ ensure
44
+ conn.close if conn
45
+ end
data/pg.gemspec CHANGED
@@ -17,8 +17,10 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = "https://github.com/ged/ruby-pg"
20
- spec.metadata["changelog_uri"] = "https://github.com/ged/ruby-pg/blob/master/History.md"
20
+ spec.metadata["changelog_uri"] = "https://github.com/ged/ruby-pg/blob/master/CHANGELOG.md"
21
21
  spec.metadata["documentation_uri"] = "http://deveiate.org/code/pg"
22
+ # https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers#msys2-library-dependency
23
+ spec.metadata["msys2_mingw_dependencies"] = "postgresql"
22
24
 
23
25
  # Specify which files should be added to the gem when it is released.
24
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -0,0 +1,30 @@
1
+ From e82c1b395162ea71279ea2170259383082e41ab0 Mon Sep 17 00:00:00 2001
2
+ From: Lars Kanis <lars@greiz-reinsdorf.de>
3
+ Date: Sat, 12 Jul 2025 10:55:17 +0200
4
+ Subject: [PATCH] Allow static linking krb5 library
5
+
6
+ Otherwise it fails with:
7
+ Undefined symbols for architecture arm64:
8
+ "_krb5int_c_mit_des_zeroblock", referenced from:
9
+ _krb5int_des3_cbc_encrypt in libk5crypto.a(d3_aead.o)
10
+ _krb5int_des3_cbc_decrypt in libk5crypto.a(d3_aead.o)
11
+ ---
12
+ src/lib/crypto/builtin/des/des_int.h | 2 +-
13
+ 1 file changed, 1 insertion(+), 1 deletion(-)
14
+
15
+ diff --git a/src/lib/crypto/builtin/des/des_int.h b/src/lib/crypto/builtin/des/des_int.h
16
+ index 46fed7dbd..114e48ebd 100644
17
+ --- a/lib/crypto/builtin/des/des_int.h
18
+ +++ b/lib/crypto/builtin/des/des_int.h
19
+ @@ -159,7 +159,7 @@ mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
20
+ const mit_des_cblock ivec, int enc);
21
+
22
+ #define mit_des_zeroblock krb5int_c_mit_des_zeroblock
23
+ -extern const mit_des_cblock mit_des_zeroblock;
24
+ +const mit_des_cblock mit_des_zeroblock;
25
+
26
+ /* fin_rndkey.c */
27
+ krb5_error_code mit_des_finish_random_key(const krb5_encrypt_block *,
28
+ --
29
+ 2.43.0
30
+
@@ -0,0 +1,21 @@
1
+ --- a/Configurations/10-main.conf
2
+ +++ b/Configurations/10-main.conf
3
+ @@ -1603,6 +1603,18 @@
4
+ multilib => "64",
5
+ },
6
+
7
+ + "mingwarm64" => {
8
+ + inherit_from => [ "mingw-common" ],
9
+ + cflags => "",
10
+ + sys_id => "MINGWARM64",
11
+ + bn_ops => add("SIXTY_FOUR_BIT"),
12
+ + asm_arch => 'aarch64',
13
+ + uplink_arch => 'armv8',
14
+ + perlasm_scheme => "win64",
15
+ + shared_rcflag => "",
16
+ + multilib => "-arm64",
17
+ + },
18
+ +
19
+ #### UEFI
20
+ "UEFI" => {
21
+ inherit_from => [ "BASE_unix" ],
@@ -0,0 +1,42 @@
1
+ From 746e8e250b265c40d9706f26560e02e8623f123f Mon Sep 17 00:00:00 2001
2
+ From: Lars Kanis <lars@greiz-reinsdorf.de>
3
+ Date: Fri, 31 Jan 2025 21:58:00 +0100
4
+ Subject: [PATCH] Use workaround of __builtin_setjmp only on MINGW on MSVCRT
5
+
6
+ Because it is not present on ARM64 on Windows and not necessary on any UCRT based toolchain.
7
+ ---
8
+ src/include/c.h | 10 +++++-----
9
+ 1 file changed, 5 insertions(+), 5 deletions(-)
10
+
11
+ diff --git a/src/include/c.h b/src/include/c.h
12
+ index a14c631516..33792c860c 100644
13
+ --- a/src/include/c.h
14
+ +++ b/src/include/c.h
15
+ @@ -1312,19 +1312,19 @@ extern int fdatasync(int fildes);
16
+ /*
17
+ * When there is no sigsetjmp, its functionality is provided by plain
18
+ * setjmp. We now support the case only on Windows. However, it seems
19
+ - * that MinGW-64 has some longstanding issues in its setjmp support,
20
+ - * so on that toolchain we cheat and use gcc's builtins.
21
+ + * that MinGW-64 on x86_64 has some longstanding issues in its setjmp
22
+ + * support, so on that toolchain we cheat and use gcc's builtins.
23
+ */
24
+ #ifdef WIN32
25
+ -#ifdef __MINGW64__
26
+ +#if defined(__MINGW64__) && !defined(_UCRT)
27
+ typedef intptr_t sigjmp_buf[5];
28
+ #define sigsetjmp(x,y) __builtin_setjmp(x)
29
+ #define siglongjmp __builtin_longjmp
30
+ -#else /* !__MINGW64__ */
31
+ +#else /* !defined(__MINGW64__) || defined(_UCRT) */
32
+ #define sigjmp_buf jmp_buf
33
+ #define sigsetjmp(x,y) setjmp(x)
34
+ #define siglongjmp longjmp
35
+ -#endif /* __MINGW64__ */
36
+ +#endif /* defined(__MINGW64__) && !defined(_UCRT) */
37
+ #endif /* WIN32 */
38
+
39
+ /* /port compatibility functions */
40
+ --
41
+ 2.43.0
42
+
@@ -0,0 +1,52 @@
1
+ From ab793829a4ce473f1cc2bbc0e2a6f6753553255d Mon Sep 17 00:00:00 2001
2
+ From: Lars Kanis <lars@greiz-reinsdorf.de>
3
+ Date: Sun, 8 Sep 2024 13:59:05 +0200
4
+ Subject: [PATCH] libpq: Process buffered SSL read bytes to support records
5
+ >8kB on async API
6
+
7
+ The async API of libpq doesn't support SSL record sizes >8kB so far.
8
+ This size isn't exceeded by vanilla PostgreSQL, but by other products using
9
+ the postgres wire protocol 3.
10
+ PQconsumeInput() reads all data readable from the socket, so that the read
11
+ condition is cleared.
12
+ But it doesn't process all the data that is pending on the SSL layer.
13
+ Also a subsequent call to PQisBusy() doesn't process it, so that the client
14
+ is triggered to wait for more readable data on the socket.
15
+ But this never arrives, so that the connection blocks infinitely.
16
+
17
+ To fix this issue call pqReadData() repeatedly until there is no buffered
18
+ SSL data left to be read.
19
+
20
+ The synchronous libpq API isn't affected, since it supports arbitrary SSL
21
+ record sizes already.
22
+ ---
23
+ src/interfaces/libpq/fe-exec.c | 13 +++++++++++++
24
+ 1 file changed, 13 insertions(+)
25
+
26
+ diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
27
+ index 0d224a852..637894ee1 100644
28
+ --- a/src/interfaces/libpq/fe-exec.c
29
+ +++ b/src/interfaces/libpq/fe-exec.c
30
+ @@ -2006,6 +2006,19 @@ PQconsumeInput(PGconn *conn)
31
+ if (pqReadData(conn) < 0)
32
+ return 0;
33
+
34
+ + #ifdef USE_SSL
35
+ + /*
36
+ + * Ensure all buffered read bytes in the SSL library are processed,
37
+ + * which might be not the case, if the SSL record size exceeds 8k.
38
+ + * Otherwise parseInput can't process the data.
39
+ + */
40
+ + while (conn->ssl_in_use && pgtls_read_pending(conn))
41
+ + {
42
+ + if (pqReadData(conn) < 0)
43
+ + return 0;
44
+ + }
45
+ + #endif
46
+ +
47
+ /* Parsing of the data waits till later. */
48
+ return 1;
49
+ }
50
+ --
51
+ 2.43.0
52
+
Binary file
@@ -0,0 +1,64 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_helper'
3
+
4
+ class PgGemHelper < Bundler::GemHelper
5
+ attr_accessor :cross_platforms
6
+
7
+ def install
8
+ super
9
+
10
+ task "release:guard_clean" => ["release:update_history"]
11
+
12
+ task "release:update_history" do
13
+ update_history
14
+ end
15
+
16
+ task "release:rubygem_push" => ["gem:native"]
17
+ end
18
+
19
+ def hfile
20
+ "CHANGELOG.md"
21
+ end
22
+
23
+ def headline
24
+ '^([^\n]*)(\d+\.\d+\.\d+(?:\.\w+)?)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)'
25
+ end
26
+
27
+ def reldate
28
+ Time.now.strftime("%Y-%m-%d")
29
+ end
30
+
31
+ def update_history
32
+ hin = File.read(hfile)
33
+ hout = hin.sub(/#{headline}/) do
34
+ raise "#{hfile} isn't up-to-date for version #{version} (!= #{$2})" unless $2==version.to_s
35
+ $1 + $2 + $3 + reldate + $5
36
+ end
37
+ if hout != hin
38
+ Bundler.ui.confirm "Updating #{hfile} for release."
39
+ File.write(hfile, hout)
40
+ Rake::FileUtilsExt.sh "git", "commit", hfile, "-m", "Update release date in #{hfile}"
41
+ end
42
+ end
43
+
44
+ def tag_version
45
+ Bundler.ui.confirm "Tag release with annotation:"
46
+ m = File.read(hfile).match(/(?<annotation>#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}")
47
+ Bundler.ui.info(m[:annotation].gsub(/^/, " "))
48
+ IO.popen(["git", "tag", "--file=-", version_tag], "w") do |fd|
49
+ fd.write m[:annotation]
50
+ end
51
+ yield if block_given?
52
+ rescue
53
+ Bundler.ui.error "Untagging #{version_tag} due to error."
54
+ Rake::FileUtilsExt.sh "git", "tag", "-d", version_tag
55
+ raise
56
+ end
57
+
58
+ def rubygem_push(path)
59
+ cross_platforms.each do |ruby_platform|
60
+ super(path.gsub(/\.gem\z/, "-#{ruby_platform}.gem"))
61
+ end
62
+ super(path)
63
+ end
64
+ end
data.tar.gz.sig CHANGED
Binary file