Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original) +++ subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Fri Jan 14 14:01:45 2022 @@ -22,7 +22,10 @@ */ package org.apache.subversion.javahl; +import static org.junit.Assert.*; + import org.apache.subversion.javahl.callback.*; +import org.apache.subversion.javahl.remote.*; import org.apache.subversion.javahl.types.*; import java.io.File; @@ -34,6 +37,7 @@ import java.io.PrintWriter; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.text.ParseException; @@ -2736,7 +2740,7 @@ public class BasicTests extends SVNTests public void singleMessage(Set<ChangePath> changedPaths, long revision, Map<String, byte[]> revprops, boolean hasChildren) - { revList.add(new Long(revision)); } + { revList.add(Long.valueOf(revision)); } }); long[] revisions = new long[revList.size()]; @@ -4093,6 +4097,7 @@ public class BasicTests extends SVNTests * @throws Throwable * @since 1.5 */ + @SuppressWarnings("deprecation") public void testBasicBlame() throws Throwable { OneTest thisTest = new OneTest(); @@ -4122,6 +4127,7 @@ public class BasicTests extends SVNTests * Test blame with diff options. * @since 1.9 */ + @SuppressWarnings("deprecation") public void testBlameWithDiffOptions() throws Throwable { OneTest thisTest = new OneTest(); @@ -4155,6 +4161,49 @@ public class BasicTests extends SVNTests } /** + * Test the new 1.12 blame interface on a file with null bytes. + * @throws Throwable + * @since 1.12 + */ + public void testBinaryBlame() throws Throwable + { + final byte[] lineIn = {0x0, 0x0, 0x0, 0xa}; + final byte[] lineOut = {0x0, 0x0, 0x0}; + + OneTest thisTest = new OneTest(); + // Modify the file iota, adding null bytes. + File iota = new File(thisTest.getWorkingCopy(), "iota"); + FileOutputStream stream = new FileOutputStream(iota, false); + stream.write(lineIn); + stream.close(); + Set<String> srcPaths = new HashSet<String>(1); + srcPaths.add(thisTest.getWCPath()); + try { + client.username("rayjandom"); + client.commit(srcPaths, Depth.infinity, false, false, null, null, + new ConstMsg("NUL bytes written to /iota"), null); + } finally { + client.username("jrandom"); + } + + // Test the current interface + BlameRangeCallbackImpl rangeCallback = new BlameRangeCallbackImpl(); + BlameLineCallbackImpl lineCallback = new BlameLineCallbackImpl(); + client.blame(thisTest.getWCPath() + "/iota", Revision.HEAD, + Revision.getInstance(0), Revision.HEAD, + false, false, null, rangeCallback, lineCallback); + assertEquals(0, rangeCallback.startRevnum); + assertEquals(2, rangeCallback.endRevnum); + assertEquals(1, lineCallback.numberOfLines()); + + BlameLineCallbackImpl.BlameLine line = lineCallback.getBlameLine(0); + assertNotNull(line); + assertEquals(2, line.getRevision()); + assertEquals("rayjandom", line.getAuthor()); + assertArrayEquals(lineOut, line.getLine()); + } + + /** * Test commit of arbitrary revprops. * @throws Throwable * @since 1.5 @@ -4370,6 +4419,320 @@ public class BasicTests extends SVNTests assertEquals("fake", new String(revprop)); } + public static int FLAG_ECHO = 0x00000001; + public static int FLAG_THROW_IN_OPEN = 0x00000002; + + public enum Actions + { + READ_CLIENT, // Read a request from SVN client + EMUL_SERVER, // Emulate server response + WAIT_TUNNEL, // Wait for tunnel to be closed + }; + + public static class ScriptItem + { + Actions action; + String value; + + ScriptItem(Actions action, String value) + { + this.action = action; + this.value = value; + } + } + + private static class TestTunnelAgent extends Thread + implements TunnelAgent + { + ScriptItem[] script; + int flags; + String error = null; + ReadableByteChannel request; + WritableByteChannel response; + + final CloseTunnelCallback closeTunnelCallback = () -> + { + if ((flags & FLAG_ECHO) != 0) + System.out.println("TunnelAgent.CloseTunnelCallback"); + }; + + TestTunnelAgent(int flags, ScriptItem[] script) + { + this.flags = flags; + this.script = script; + } + + public void joinAndTest() + { + try + { + join(); + } + catch (InterruptedException e) + { + fail("InterruptedException was caught"); + } + + if (error != null) + fail(error); + } + + @Override + public boolean checkTunnel(String name) + { + return true; + } + + private String readClient(ByteBuffer readBuffer) + throws IOException + { + readBuffer.reset(); + request.read(readBuffer); + + final int offset = readBuffer.arrayOffset(); + return new String(readBuffer.array(), + offset, + readBuffer.position() - offset); + } + + private void emulateServer(String serverMessage) + throws IOException + { + final byte[] responseBytes = serverMessage.getBytes(); + response.write(ByteBuffer.wrap(responseBytes)); + } + + private void doScriptItem(ScriptItem scriptItem, ByteBuffer readBuffer) + throws Exception + { + switch (scriptItem.action) + { + case READ_CLIENT: + final String actualLine = readClient(readBuffer); + + if ((flags & FLAG_ECHO) != 0) + { + System.out.println("SERVER: " + scriptItem.value); + System.out.flush(); + } + + if (!actualLine.contains(scriptItem.value)) + { + System.err.println("Expected: " + scriptItem.value); + System.err.println("Actual: " + actualLine); + System.err.flush(); + + // Unblock the SVN thread by emulating a server error + final String serverError = "( success ( ( ) 0: ) ) ( failure ( ( 160000 39:Test script received unexpected request 0: 0 ) ) ) "; + emulateServer(serverError); + + fail("Unexpected client request"); + } + break; + case EMUL_SERVER: + if ((flags & FLAG_ECHO) != 0) + { + System.out.println("CLIENT: " + scriptItem.value); + System.out.flush(); + } + + emulateServer(scriptItem.value); + break; + case WAIT_TUNNEL: + // The loop will end with an exception when tunnel is closed + for (;;) + { + readClient(readBuffer); + } + } + } + + public void run() + { + final ByteBuffer readBuffer = ByteBuffer.allocate(1024 * 1024); + readBuffer.mark(); + + for (ScriptItem scriptItem : script) + { + try + { + doScriptItem(scriptItem, readBuffer); + } + catch (ClosedChannelException ex) + { + // Expected when closed properly + } + catch (IOException e) + { + // IOException occurs when already-freed apr_file_t was lucky + // to have reasonable fields to avoid the crash. It still + // indicates a problem. + error = "IOException was caught in run()"; + return; + } + catch (Throwable t) + { + // No other exceptions are expected here. + error = "Exception was caught in run()"; + t.printStackTrace(); + return; + } + } + } + + @Override + public CloseTunnelCallback openTunnel(ReadableByteChannel request, + WritableByteChannel response, + String name, + String user, + String hostname, + int port) + throws Throwable + { + this.request = request; + this.response = response; + + start(); + + if ((flags & FLAG_THROW_IN_OPEN) != 0) + throw ClientException.fromException(new RuntimeException("Test exception")); + + return closeTunnelCallback; + } + }; + + /** + * Test scenario which previously caused a JVM crash. + * In this scenario, GC is invoked before closing tunnel. + */ + public void testCrash_RemoteSession_nativeDispose() + { + final ScriptItem[] script = new ScriptItem[] + { + new ScriptItem(Actions.EMUL_SERVER, "( success ( 2 2 ( ) ( edit-pipeline svndiff1 absent-entries commit-revprops depth log-revprops atomic-revprops partial-replay inherited-props ephemeral-txnprops file-revs-reverse ) ) ) "), + new ScriptItem(Actions.READ_CLIENT, "edit-pipeline"), + new ScriptItem(Actions.EMUL_SERVER, "( success ( ( ANONYMOUS ) 36:0113e071-0208-4a7b-9f20-3038f9caf0f0 ) ) "), + new ScriptItem(Actions.READ_CLIENT, "ANONYMOUS"), + new ScriptItem(Actions.EMUL_SERVER, "( success ( ) ) ( success ( 36:00000000-0000-0000-0000-000000000000 25:svn+test://localhost/test ( mergeinfo ) ) ) "), + }; + + final TestTunnelAgent tunnelAgent = new TestTunnelAgent(0, script); + final RemoteFactory remoteFactory = new RemoteFactory(); + remoteFactory.setTunnelAgent(tunnelAgent); + + ISVNRemote remote = null; + try + { + remote = remoteFactory.openRemoteSession("svn+test://localhost/test", 1); + } + catch (SubversionException e) + { + fail("SubversionException was caught"); + } + + // Previously, 'OperationContext::openTunnel()' didn't 'NewGlobalRef()' + // callback returned by 'TunnelAgent.openTunnel()'. This caused JVM to + // dispose it on next GC. JavaHL calls callback in 'remote.dispose()'. + // If the callback was disposed, this caused a JVM crash. + System.gc(); + remote.dispose(); + + tunnelAgent.joinAndTest(); + } + + /** + * Test scenario which previously caused a JVM crash. + * In this scenario, tunnel was not properly closed after exception in + * 'TunnelAgent.openTunnel()'. + */ + public void testCrash_RequestChannel_nativeRead_AfterException() + { + // Previously, exception caused TunnelChannel's native side to be + // destroyed with the following abbreviated stack: + // TunnelChannel.nativeClose() + // svn_pool_destroy(sesspool) + // svn_ra_open5() + // TunnelAgent was unaware and called 'RequestChannel.nativeRead()' + // or 'ResponseChannel.nativeWrite()', causing either a crash or + // an attempt to use a random file. + final int flags = FLAG_THROW_IN_OPEN; + + final ScriptItem[] script = new ScriptItem[] + { + new ScriptItem(Actions.EMUL_SERVER, "( success ( 2 2 ( ) ( edit-pipeline svndiff1 absent-entries commit-revprops depth log-revprops atomic-revprops partial-replay inherited-props ephemeral-txnprops file-revs-reverse ) ) ) "), + new ScriptItem(Actions.WAIT_TUNNEL, ""), + }; + + final TestTunnelAgent tunnelAgent = new TestTunnelAgent(flags, script); + final SVNClient svnClient = new SVNClient(); + svnClient.setTunnelAgent(tunnelAgent); + + try + { + svnClient.openRemoteSession("svn+test://localhost/test"); + } + catch (SubversionException e) + { + // RuntimeException("Test exception") is expected here + } + + tunnelAgent.joinAndTest(); + } + + /** + * Test scenario which previously caused a JVM crash. + * In this scenario, tunnel was not properly closed after an SVN error. + */ + public void testCrash_RequestChannel_nativeRead_AfterSvnError() + { + final String wcRoot = new File("tempSvnRepo").getAbsolutePath(); + + final ScriptItem[] script = new ScriptItem[] + { + // openRemoteSession + new ScriptItem(Actions.EMUL_SERVER, "( success ( 2 2 ( ) ( edit-pipeline svndiff1 absent-entries commit-revprops depth log-revprops atomic-revprops partial-replay inherited-props ephemeral-txnprops file-revs-reverse ) ) ) "), + new ScriptItem(Actions.READ_CLIENT, "edit-pipeline"), + new ScriptItem(Actions.EMUL_SERVER, "( success ( ( ANONYMOUS ) 36:0113e071-0208-4a7b-9f20-3038f9caf0f0 ) ) "), + new ScriptItem(Actions.READ_CLIENT, "ANONYMOUS"), + new ScriptItem(Actions.EMUL_SERVER, "( success ( ) ) ( success ( 36:00000000-0000-0000-0000-000000000000 25:svn+test://localhost/test ( mergeinfo ) ) ) "), + // checkout + new ScriptItem(Actions.READ_CLIENT, "( get-latest-rev ( ) ) "), + // Previously, error caused a SubversionException to be created, + // which then skipped closing the Tunnel properly due to + // 'ExceptionOccurred()' in 'OperationContext::closeTunnel()'. + // If TunnelAgent was unaware and called 'RequestChannel.nativeRead()', + // it either crashed or tried to use a random file. + new ScriptItem(Actions.EMUL_SERVER, "( success ( ( ) 0: ) ) ( failure ( ( 160006 20:This is a test error 0: 0 ) ) ) "), + // Pretend that TunnelAgent tries to read more + new ScriptItem(Actions.WAIT_TUNNEL, ""), + }; + + final TestTunnelAgent tunnelAgent = new TestTunnelAgent(0, script); + final SVNClient svnClient = new SVNClient(); + svnClient.setTunnelAgent(tunnelAgent); + + try + { + svnClient.checkout("svn+test://localhost/test", + wcRoot, + Revision.getInstance(1), + null, + Depth.infinity, + true, + false); + + svnClient.dispose(); + } + catch (ClientException ex) + { + final int SVN_ERR_FS_NO_SUCH_REVISION = 160006; + if (SVN_ERR_FS_NO_SUCH_REVISION != ex.getAllMessages().get(0).getCode()) + ex.printStackTrace(); + } + + tunnelAgent.joinAndTest(); + } + /** * @return <code>file</code> converted into a -- possibly * <code>canonical</code>-ized -- Subversion-internal path @@ -4679,6 +5042,7 @@ public class BasicTests extends SVNTests return callback.getMessages(); } + @SuppressWarnings("deprecation") private byte[] collectBlameLines(String path, Revision pegRevision, Revision revisionStart, Revision revisionEnd, @@ -4766,6 +5130,7 @@ public class BasicTests extends SVNTests } /* A blame callback implementation. */ + @SuppressWarnings("deprecation") protected class BlameCallbackImpl implements BlameCallback { @@ -4978,6 +5343,158 @@ public class BasicTests extends SVNTests } } } + + /* A blame range callback implementation. */ + protected class BlameRangeCallbackImpl implements BlameRangeCallback + { + public long startRevnum = -1; + public long endRevnum = -1; + public void setRange(long start, long end) + { + startRevnum = start; + endRevnum = end; + } + } + + /* A blame line callback implementation. */ + protected class BlameLineCallbackImpl implements BlameLineCallback + { + + /** list of blame records (lines) */ + private List<BlameLine> lines = new ArrayList<BlameLine>(); + + public void singleLine(long lineNum, long rev, + Map<String, byte[]> revProps, + long mergedRevision, + Map<String, byte[]> mergedRevProps, + String mergedPath, boolean localChange, + byte[] line) + throws ClientException + { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + + try { + insertLine( + df.parse(new String(revProps.get("svn:date"))), + rev, + new String(revProps.get("svn:author")), + mergedRevProps == null ? null + : df.parse(new String(mergedRevProps.get("svn:date"))), + mergedRevision, + mergedRevProps == null ? null + : new String(mergedRevProps.get("svn:author")), + mergedPath, line); + } catch (ParseException e) { + throw ClientException.fromException(e); + } + } + + private Date getDate(Date date, Date merged_date) { + return (merged_date == null ? date : merged_date); + } + + private String getAuthor(String author, String merged_author) { + return (merged_author == null ? author : merged_author); + } + + private long getRevision(long revision, long merged_revision) { + return (merged_revision == -1 ? revision : merged_revision); + } + + private void insertLine(Date date, long revision, String author, + Date merged_date, long merged_revision, + String merged_author, String merged_path, + byte[] line) + { + this.lines.add(new BlameLine(getRevision(revision, merged_revision), + getAuthor(author, merged_author), + getDate(date, merged_date), + line)); + } + + /** + * Retrieve the number of line of blame information + * @return number of lines of blame information + */ + public int numberOfLines() + { + return this.lines.size(); + } + + /** + * Retrieve blame information for specified line number + * @param i the line number to retrieve blame information about + * @return Returns object with blame information for line + */ + public BlameLine getBlameLine(int i) + { + if (i >= this.lines.size()) + { + return null; + } + return this.lines.get(i); + } + + /** + * Class represeting one line of the lines, i.e. a blame record + */ + public final class BlameLine + { + private long revision; + private String author; + private Date changed; + private byte[] line; + + /** + * Constructor + * + * @param revision + * @param author + * @param changed + * @param line + */ + public BlameLine(long revision, String author, + Date changed, byte[] line) + { + this.revision = revision; + this.author = author; + this.changed = changed; + this.line = line; + } + + /** + * @return Returns the author. + */ + public String getAuthor() + { + return author; + } + + /** + * @return Returns the date changed. + */ + public Date getChanged() + { + return changed; + } + + /** + * @return Returns the source line content. + */ + public byte[] getLine() + { + return line; + } + + /** + * @return Returns the revision. + */ + public long getRevision() + { + return revision; + } + } + } /** A helper which calls update with a bunch of default args. */ private long update(OneTest thisTest)
Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java (original) +++ subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/ExceptionTests.java Fri Jan 14 14:01:45 2022 @@ -206,18 +206,17 @@ public class ExceptionTests extends SVNT { client.blame(thisTest.getWorkingCopy() + "/iota", Revision.getInstance(1), Revision.getInstance(1), - Revision.getInstance(1), false, false, - new BlameCallback() - { - public void singleLine(long lineNum, long revision, - Map<String, byte[]> revProps, long mergedRevision, - Map<String, byte[]> mergedRevProps, - String mergedPath, String line, - boolean localChange) - { - throw new TestException("inner", theException); - } - }); + Revision.getInstance(1), false, false, null, null, + new BlameLineCallback() { + public void singleLine(long lineNum, long revision, + Map<String, byte[]> revProps, long mergedRevision, + Map<String, byte[]> mergedRevProps, + String mergedPath, boolean localChange, + byte[] line) + { + throw new TestException("inner", theException); + } + }); } catch (ClientException e) { Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java (original) +++ subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java Fri Jan 14 14:01:45 2022 @@ -1383,9 +1383,9 @@ public class SVNRemoteTests extends SVNT { ISVNRemote session = getSession(); - Long expected = new Long(1L); + Long expected = Long.valueOf(1L); ArrayList<Long> revs = new ArrayList<Long>(3); - revs.add(new Long(0L)); + revs.add(Long.valueOf(0L)); revs.add(expected); Map<Long, String> locs = session.getLocations("A", 1, revs); Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java (original) +++ subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java Fri Jan 14 14:01:45 2022 @@ -224,7 +224,7 @@ class SVNTests extends TestCase rootUrl = rootUrl.replaceFirst("file:/", "file:///"); // According to - // http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#toURL() + // https://docs.oracle.com/javase/1.5.0/docs/api/java/io/File.html#toURL() // the URL from rootDir.toURI() may end with a trailing / // if rootDir exists and is a directory, so depending if // the test suite has been previously run and rootDir Modified: subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/SVNTests.java URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/SVNTests.java?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/SVNTests.java (original) +++ subversion/branches/multi-wc-format/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/SVNTests.java Fri Jan 14 14:01:45 2022 @@ -183,7 +183,7 @@ class SVNTests extends TestCase rootUrl = rootUrl.replaceFirst("file:/", "file:///"); // According to - // http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#toURL() + // https://docs.oracle.com/javase/1.5.0/docs/api/java/io/File.html#toURL() // the URL from rootDir.toURI() may end with a trailing / // if rootDir exists and is a directory, so depending if // the test suite has been previously run and rootDir Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/INSTALL URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/INSTALL?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/INSTALL (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/INSTALL Fri Jan 14 14:01:45 2022 @@ -5,7 +5,12 @@ STATUS OF THE SWIG BINDINGS * Python The Python bindings are fairly well developed, although there are some - missing parts. + missing parts. We support both of Python 2.7 and Python 3.x; however, + SWIG Python bindings for different versions of Python cannot be + simultaneously installed in the same environment, because they need to + install mutually incompatible C shared libraries under the same name. The + distribution tarballs are shipped with SWIG-generated C source files for + Python 3.x. (N.B. As discussed below, they will not compile in Debug mode on Windows.) @@ -64,15 +69,36 @@ STATUS OF THE SWIG BINDINGS BUILDING SWIG BINDINGS FOR SVN ON UNIX -Step 1: Install a suitable version of SWIG (which is - currently SWIG version 1.3.24 or later). +Step 1: [Optional] Install a suitable version of SWIG - * Perhaps your distribution packages a suitable version - if it does - install it, and skip to the last bullet point in this section. + * SWIG installation is optional. You do not need to install SWIG + if you are using a Subversion distribution tarball because it already + contains the source files generated by SWIG. You will need a suitable + version of SWIG if you are using a working copy of Subversion's sources + checked out from the repository; if you want to generate the SWIG + language bindings C source files by yourself; or if you want to build + Python 2.x bindings (since the SWIG-generated C source files in the + distribution tarballs target Python 3.x). + + * We currently support SWIG versions 2.0.0 and later, with the + following notes: + - SWIG 1.3.24 and later 1.3.x may work, but we do not test these + versions on our latest source code. + - For Python 2 bindings, SWIG 4.0.0 or later is not supported. + - For Python 3 bindings, SWIG 3.0.10 or later is required. + - Note that SWIG 3.0.9 has some trouble with Python support. + (See https://sourceforge.net/p/swig/news/2016/06/swig-3010-released/) + - For Perl 5.16 and later, SWIG 2.0.8 or later is required. + - For Ruby bindings, SWIG 3.0.8 is not supported. + + * Perhaps your distribution packages a suitable version of SWIG. + If so, install it and skip to the last bullet point of this + section. * Go to http://www.swig.org/, download the source tarball, and unpack. - * In the SWIG-1.3.xx directory, run ./configure. + * In the swig-x.y.z, directory, run ./configure (where x.y.z is + SWIG version, e.g., 3.0.12). If you plan to build the Python bindings, and have a system with more than one version of Python installed, you may need @@ -95,43 +121,74 @@ Step 1: Install a suitable version of S Run 'make && make install' * To verify you have SWIG installed correctly, run "swig -version" - from the command line. SWIG should report that it is version 1.3.24 - or newer. + from the command line. SWIG should report that it is one of the + suitable versions mentioned above. + + +Step 1a: Install py3c library if building Python SWIG bindings. + + * Check your distribution packages first for a suitable version, and + if found install from there. + + * To install from source, download the latest release from + https://github.com/encukou/py3c. + + * This is a header-only library, so no configuring or compiling is + necessary, simply 'make install'. + Step 2: Build and Install Subversion. See Subversion's own INSTALL file for details. - Make sure that Subversion's ./configure script sees your installed SWIG! + If you are using a Subversion distribution tarball and want to rebuild + the SWIG language bindings C source files with your installed SWIG, + you need to execute autogen.sh, because the bundled configure script + and makefiles don't support it. + + If you don't use SWIG bindings C source files already generated, + make sure that Subversion's ./configure script sees your installed SWIG! It tries to detect SWIG near the very end of its output. + You can find it by running 'grep "^SWIG=" config.log'. - Also make sure that the configure script sees the paths to the perl and/or - python executable you used to configure SWIG as above. If it does not then - you can specify the correct path by adding PYTHON=/path/to/python or - PERL=/path/to/perl onto the command line for configure. For example: - ./configure PYTHON=/usr/bin/python2.7 PERL=/usr/bin/perl5.8.0 + Also make sure that the configure script sees the paths to the perl, + ruby, and/or python executable you used to configure SWIG as above. + If it does not then you can specify the correct path by specifying + --with-swig-python=/path/to/python, --with-swig-perl=/path/to/perl, + and/or --with-swig-ruby=/path/to/ruby to the command line for configure. + For example: + ./configure --with-swig-python=/usr/bin/python3.7 \ + --with-swig-perl=/usr/bin/perl5.28.2 \ + --with-swig-ruby=/usr/bin/ruby2.7 If Subversion's ./configure finds a SWIG that it's happy with, then it will build special glue libraries to link svn to the swig bindings: - libsvn_swig_py.so (for Python) - libsvn_swig_perl.so (for Perl) - + libsvn_swig_py-1.so (for Python) + libsvn_swig_perl-1.so (for Perl) + libsvn_swig_ruby-1.so (for Ruby) Step 3: Install Specific Language Bindings * Python - 1. Run 'make swig-py' from the top of the Subversion build tree, + 1. (Optional) If you want to build Python bindings for a version of + Python than other than that the prebuilt bindings C sources target + (e.g., if you use the Subversion distribution tarball but want to build + Python 2 bindings), run 'make clean-swig-py' from the top of the + Subversion build tree, to ensure not to use incompatible version of + bindings source files. + + 2. Run 'make swig-py' from the top of the Subversion build tree, to build the bindings. (This will invoke SWIG on the *.i files, resulting in a collection of .c source files. It will then compile and link those .c files into Python libraries.) - 2. Run 'make check-swig-py' from the top of the Subversion build - tree, to test the bindings + 3. Run 'make check-swig-py' from the top of the Subversion build + tree, to test the bindings - 3. Run 'make install-swig-py' (as root, typically) + 4. Run 'make install-swig-py' (as root, typically) from the top of the Subversion build tree. This will copy your new Python libraries into the appropriate system location. @@ -145,14 +202,14 @@ Step 3: Install Specific Language Bindi example of doing this for building rpms looks like 'make install-swig-py DESTDIR=$RPM_BUILD_ROOT/usr'. - 4. Make sure that whatever directory the bindings got installed in + 5. Make sure that whatever directory the bindings got installed in is in your Python search path. That directory depends on how you installed; a typical location is /usr/local/lib/svn-python/. There are several ways to do this. See Python's documentation for 'sys.path' and 'PYTHONPATH'. A nice way to do this is: $ echo /usr/local/lib/svn-python \ - > /usr/lib/python2.x/site-packages/subversion.pth + > /usr/lib/python3.x/site-packages/subversion.pth You may also need to update your operating system's dynamic linker configuration to enable Python to load these new libraries. On some @@ -162,15 +219,15 @@ Step 3: Install Specific Language Bindi * Perl Perl 5.8.0 is required. You can specify the perl binary by passing - PERL=/path/to/perl as part of the configure command in the top level - of the Subversion source tree. Make sure that the Perl version used - is the same one that you configured SWIG to run against during the - SWIG configure (see above). + --with-swig-perl=/path/to/perl as an option to the configure command + in the top level of the Subversion source tree. Make sure that the + Perl version used is the same one that you configured SWIG to run + against during the SWIG configure (see above). 1. Run `make swig-pl' from the top of the Subversion build tree. 2. Run `make check-swig-pl' from the top of the Subversion build - tree, to test the bindings + tree, to test the bindings 3. to install run `make install-swig-pl' from the top of the Subversion build tree. @@ -182,9 +239,9 @@ Step 3: Install Specific Language Bindi 2. Run `make install-swig-pl-lib' - 3. cd subversion/bindings/swig/perl/native + 3. cd subversion/bindings/swig/perl/native - 4. Run `perl Makefile.PL EXTRAOPTIONSHERE` + 4. Run `perl Makefile.PL EXTRAOPTIONSHERE` 5. Run `make install' @@ -194,21 +251,22 @@ Step 3: Install Specific Language Bindi * Ruby - + 1. Run `make swig-rb' from the top of the Subversion build tree, to build the bindings. 2. Run `make check-swig-rb' from the top of the Subversion build tree, to test the bindings. - 3. To install, run `make install-swig-rb' from the top of the + 3. To install, run `make install-swig-rb' from the top of the Subversion build tree. - You can specify the ruby binary by passing RUBY=/path/to/ruby as part - of the configure command in the top level of the Subversion source - tree. Make sure that the Ruby version used is the same one that you - configured SWIG to run against during the SWIG configure (see above). - + You can specify the ruby binary by passing --with-swig-ruby=/path/to/ruby + as an option to the configure command in the top level of the + Subversion source tree. Make sure that the Ruby version used is + the same one that you configured SWIG to run against during the + SWIG configure (see above). + BUILDING SWIG BINDINGS FOR SVN ON WINDOWS @@ -226,6 +284,9 @@ BUILDING SWIG BINDINGS FOR SVN ON WINDOW http://www.python.org/ http://www.activestate.com/ActivePerl/ + If you plan to build python bindings, you will also need to download and + extract the py3c library from https://github.com/encukou/py3c/releases. + NOTE: Our Python SWIG bindings will currently NOT compile in Debug mode unless you have python24_d.lib (which binary distributions of Python do not contain). Therefore, the Python bindings will only @@ -242,6 +303,11 @@ BUILDING SWIG BINDINGS FOR SVN ON WINDOW > gen-make.py <other options> --with-swig="C:\Program Files\SWIG-2.0.2" + If you are building python bindings, point to the py3c directory as well: + + > gen-make.py <other options> --with-swig="C:\Program Files\SWIG-2.0.2" \ + --with-py3c="C:\SVN\py3c" + 4. If you haven't already built Subversion, you should do so now. Instructions are in the main INSTALL file. @@ -324,12 +390,12 @@ TESTING SWIG BINDINGS * Perl The Perl bindings are using the standard module testing facilities - to do regression tests. Simply run 'make check-swig-pl' as described in + to do regression tests. Simply run 'make check-swig-pl' as described in the install section. * Ruby - To test the Ruby bindings, simply run `make check-swig-rb' as described + To test the Ruby bindings, simply run `make check-swig-rb' as described in the install section. @@ -361,7 +427,7 @@ USING SWIG BINDINGS sample/demo programs found in tools/examples/ in the Subversion source code tree. Additionally, there are several third-party tools that make use of these bindings, including ViewVC - (http://viewvc.tigris.org/) and Trac (http://trac.edgewall.org/). + (http://www.viewvc.org/) and Trac (https://trac.edgewall.org/). * Perl Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/core.i URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/core.i?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/core.i (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/core.i Fri Jan 14 14:01:45 2022 @@ -23,16 +23,16 @@ * of the more specific module files. */ +%include svn_global.swg + #if defined(SWIGPYTHON) -%module(package="libsvn") core +%module(package="libsvn", moduleimport=SVN_PYTHON_MODULEIMPORT) core #elif defined(SWIGPERL) %module "SVN::_Core" #elif defined(SWIGRUBY) %module "svn::ext::core" #endif -%include svn_global.swg - %{ #include <apr.h> #include <apr_general.h> @@ -362,7 +362,9 @@ /* svn_config_get */ const char *default_value, /* svn_config_read_auth_data */ - const char *config_dir, + const char *config_dir, + /* svn_config_get_user_config_path */ + const char *fname, /* svn_diff_file_output_merge */ const char *conflict_original, const char *conflict_modified, @@ -381,6 +383,7 @@ if (PyLong_Check($input)) { temp = PyLong_AsUnsignedLong($input); } +%#if IS_PY3 != 1 else if (PyInt_Check($input)) { /* wish there was a PyInt_AsUnsignedLong but there isn't the mask version doesn't do bounds checking for us. @@ -389,6 +392,7 @@ problem goes away because PyInt is gone anyway. */ temp = PyInt_AsUnsignedLongMask($input); } +%#endif else { PyErr_SetString(PyExc_TypeError, "expecting an integer for the buffer size"); @@ -418,7 +422,7 @@ #ifdef SWIGPYTHON %typemap(argout) (char *buffer, apr_size_t *len) { - %append_output(PyString_FromStringAndSize($1, *$2)); + %append_output(PyBytes_FromStringAndSize($1, *$2)); free($1); } #endif @@ -440,13 +444,24 @@ */ #ifdef SWIGPYTHON %typemap(in) (const char *data, apr_size_t *len) ($*2_type temp) { - if (!PyString_Check($input)) { + Py_ssize_t length; + if (PyBytes_Check($input)) { + if (PyBytes_AsStringAndSize($input, (char **)&$1, &length) == -1) { + SWIG_fail; + } + } + else if (PyUnicode_Check($input)) { + $1 = (char *)PyStr_AsUTF8AndSize($input, &length); + if (PyErr_Occurred()) { + SWIG_fail; + } + } + else { PyErr_SetString(PyExc_TypeError, - "expecting a string for the buffer"); + "expecting a bytes or str object for the buffer"); SWIG_fail; } - $1 = PyString_AS_STRING($input); - temp = PyString_GET_SIZE($input); + temp = ($*2_type)length; $2 = ($2_ltype)&temp; } #endif @@ -499,8 +514,8 @@ SWIG_fail; } - if (PyString_Check($input)) { - char *value = PyString_AS_STRING($input); + if (PyBytes_Check($input)) { + const char *value = PyBytes_AsString($input); $1 = apr_pstrdup(_global_pool, value); } else if (PyLong_Check($input)) { @@ -605,7 +620,7 @@ */ #ifdef SWIGPYTHON %typemap(in) FILE * { - $1 = PyFile_AsFile($input); + $1 = svn_swig_py_as_file($input); if ($1 == NULL) { PyErr_SetString(PyExc_ValueError, "Must pass in a valid file object"); SWIG_fail; @@ -710,11 +725,6 @@ core_set_current_pool (apr_pool_t *pool) svn_swig_rb_config_section_enumerator) #endif -/* Allow None to be passed as config_dir argument */ -#ifdef SWIGPYTHON -%typemap(in,parse="z") const char *config_dir ""; -#endif - /* ----------------------------------------------------------------------- thunk the various authentication prompt functions. PERL NOTE: store the inputed SV in _global_callback for use in the @@ -816,6 +826,7 @@ core_set_current_pool (apr_pool_t *pool) %include svn_error_codes_h.swg %include svn_time_h.swg +%include svn_types_impl_h.swg %include svn_types_h.swg %include svn_pools_h.swg %include svn_version_h.swg @@ -827,6 +838,7 @@ core_set_current_pool (apr_pool_t *pool) %include svn_props_h.swg #pragma SWIG nowarn=+305 +%include svn_opt_impl_h.swg %include svn_opt_h.swg %include svn_cmdline_h.swg %include svn_auth_h.swg Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.py (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.py Fri Jan 14 14:01:45 2022 @@ -12,23 +12,57 @@ if "_is_valid" in self.__dict__: assert self.__dict__["_is_valid"](), "Variable has already been deleted" - def __getattr__(self, name): - """Get an attribute from this object""" - self.assert_valid() - - value = _swig_getattr(self, self.__class__, name) - - # If we got back a different object than we have, we need to copy all our - # metadata into it, so that it looks identical - members = self.__dict__.get("_members") - if members is not None: - _copy_metadata_deep(value, members.get(name)) + def _retrieve_swig_value(self, name, value): + # If we got back a different object than we have cached, we need to copy + # all our metadata into it, so that it looks identical to the one + # originally set. + members = self.__dict__.get('_members') + if members is not None and name in members: + _copy_metadata_deep(value, members[name]) # Verify that the new object is good _assert_valid_deep(value) return value + # Attribute access must be intercepted to ensure that objects coming from + # read attribute access match those that are set with write attribute access. + # Specifically the metadata, such as the associated apr_pool object, should + # match the originally assigned object. + # + # For classic classes it is enough to use __getattr__ to intercept swig + # derived attributes. However, with new style classes SWIG makes use of + # descriptors which mean that __getattr__ is never called. Therefore, + # __getattribute__ must be used for the interception. + + if _newclass: + def __getattribute__(self, name): + """Manage access to all attributes of this object.""" + + # Start by mimicking __getattr__ behavior: immediately return __dict__ or + # items directly present in __dict__ + mydict = object.__getattribute__(self, '__dict__') + + if name == "__dict__": + return mydict + + if name in mydict: + return mydict[name] + + object.__getattribute__(self, 'assert_valid')() + + value = _get_instance_attr(self, name) + fn = object.__getattribute__(self, '_retrieve_swig_value') + return fn(name, value) + else: + def __getattr__(self, name): + """Get an attribute from this object""" + self.assert_valid() + + value = _swig_getattr(self, self.__class__, name) + + return self._retrieve_swig_value(name, value) + def __setattr__(self, name, value): """Set an attribute on this object""" self.assert_valid() @@ -38,4 +72,4 @@ # SWIG-land self.__dict__.setdefault("_members",{})[name] = value - return _swig_setattr(self, self.__class__, name, value) + return _set_instance_attr(self, name, value) Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy.swg Fri Jan 14 14:01:45 2022 @@ -36,8 +36,8 @@ if value is None or old_value is None or value is old_value: return if isinstance(value, dict): - for k, v in value.iteritems(): - _copy_metadata_deep(v, old_value[k]) + for k in value: + _copy_metadata_deep(value[k], old_value[k]) elif isinstance(value, list): for v, old_v in zip(value, old_value): _copy_metadata_deep(v, old_v) @@ -50,15 +50,72 @@ def _assert_valid_deep(value): """Assert value's validity, recursively traversing lists and dicts.""" if isinstance(value, dict): - for v in value.itervalues(): - _assert_valid_deep(v) + for k in value: + _assert_valid_deep(value[k]) elif isinstance(value, list): for v in value: _assert_valid_deep(v) - else: - if hasattr(value, "assert_valid"): - value.assert_valid() + # Ensure that the passed in value isn't a type, which could have an + # assert_valid attribute, but it can not be called without an instance. + elif type(value) != type: + try: + fn = value.assert_valid + except AttributeError: + pass + else: + fn() + +%} +#if defined(SWIGPYTHON_PY3) +#if SWIG_VERSION >= 0x040000 +%pythoncode %{ + # -classic and -modern options have been dropped and this variable + # is not generated since SWIG 4 + _newclass = 1 + _get_instance_attr = object.__getattribute__ + _set_instance_attr = _swig_setattr_nondynamic_instance_variable(object.__setattr__) + +%} +#else +%pythoncode %{ + # SWIG classes generated with -modern do not define this variable + try: + _newclass + except NameError: + _newclass = 1 + else: + raise RuntimeError("Require -modern option, but _newclass is defined") + + _get_instance_attr = object.__getattribute__ + _set_instance_attr = _swig_setattr_nondynamic_method(object.__setattr__) + +%} +#endif +#else +%pythoncode %{ + # SWIG classes generated with -classic do not define this variable, + # so set it to 0 when it doesn't exist + try: + _newclass + except NameError: + _newclass = 0 + + if _newclass: + def _get_instance_attr(self, name): + try: + return object.__getattribute__(self, name) + except AttributeError: + return _swig_getattr(self, object.__getattribute__(self, '__class__'), + name) + else: + def _get_instance_attr(self, name): + return _swig_getattr(self, self.__class__, name) + + def _set_instance_attr(self, name, value): + return _swig_setattr(self, self.__class__, name, value) + %} +#endif /* Default code for all wrapped proxy classes in Python. * Inline the code from a separate file to avoid issues with Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy_apr.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy_apr.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy_apr.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/proxy_apr.swg Fri Jan 14 14:01:45 2022 @@ -84,6 +84,7 @@ class GenericSWIGWrapper: def set_parent_pool(self, pool): """Set the parent pool of this object""" self._parent_pool = pool + self._is_valid = weakref.ref(pool._is_valid) def valid(self): """Is this object valid?""" @@ -99,8 +100,14 @@ class GenericSWIGWrapper: return self.this def _mark_weakpool_invalid(weakpool): - if weakpool and weakpool() and hasattr(weakpool(), "_is_valid"): - del weakpool()._is_valid + if weakpool: + pool = weakpool() + if pool: + try: + del pool._is_valid + except AttributeError: + pass + %} @@ -133,7 +140,17 @@ struct apr_pool_t { def valid(self): """Check whether this memory pool and its parents are still valid""" - return hasattr(self,"_is_valid") + try: + self._is_valid + except AttributeError: + return False + # We must check whether the parent pool is valid even if + # the pool is valid because weakref's callback is not + # invoked when it is finalized by cyclic garbage collector + if self._parent_pool: + return self._parent_pool.valid() + else: + return True def assert_valid(self): """Assert that this memory_pool is still valid.""" @@ -164,10 +181,15 @@ struct apr_pool_t { self._svn_swig_py_clear_application_pool() # Mark self as invalid - if hasattr(self, "_parent_pool"): + try: del self._parent_pool - if hasattr(self, "_is_valid"): + except AttributeError: + pass + + try: del self._is_valid + except AttributeError: + pass def __del__(self): """Automatically destroy memory pools, if necessary""" @@ -200,8 +222,11 @@ struct apr_pool_t { def _wrap(self, obj): """Mark a SWIG object as owned by this pool""" self.assert_valid() - if hasattr(obj, "set_parent_pool"): - obj.set_parent_pool(self) + + fn = getattr(obj, 'set_parent_pool', None) + + if fn is not None: + fn(self) return obj elif obj is None: return None Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_containers.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_containers.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_containers.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_containers.swg Fri Jan 14 14:01:45 2022 @@ -527,7 +527,10 @@ apr_array_header_t **logfiles, apr_array_header_t **names_p, apr_array_header_t **targets_p, - apr_array_header_t **args_p + apr_array_header_t **args_p, + apr_array_header_t **props_conflicted, + apr_array_header_t **possible_moved_to_repos_relpaths, + apr_array_header_t **possible_moved_to_abspaths }; /* ----------------------------------------------------------------------- @@ -577,6 +580,40 @@ } #endif +/* ----------------------------------------------------------------------- + apr_array_header_t **options + For svn_client_conflict_option_t +*/ + +#ifdef SWIGPYTHON +%typemap(argout) apr_array_header_t **options { + %append_output + (svn_swig_py_pointerlist_to_list(*$1, + $descriptor(svn_client_conflict_option_t *), + _global_py_pool)); + if (PyErr_Occurred()) { + SWIG_fail; + } +} +#endif + +/* ----------------------------------------------------------------------- + apr_array_header_t **versions_p + For svn_client__shelf_get_all_versions +*/ + +#ifdef SWIGPYTHON +%typemap(argout) apr_array_header_t **versions_p { + %append_output + (svn_swig_py_pointerlist_to_list(*$1, + $descriptor(svn_client__shelf_version_t *), + _global_py_pool)); + if (PyErr_Occurred()) { + SWIG_fail; + } +} +#endif + /* ======================================================================= %typemap(in) apr_array_header_t * */ Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_global.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_global.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_global.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_global.swg Fri Jan 14 14:01:45 2022 @@ -31,6 +31,17 @@ #define SVN_DEPRECATED #endif +#ifdef SWIGPYTHON +%begin %{ +#define SWIG_PYTHON_STRICT_BYTE_CHAR +#if defined(_MSC_VER) +/* Prevent "non-constant aggregate initializer" errors from Python.h in + * Python 3.9 */ +# pragma warning(default : 4204) +#endif +%} +#endif + %include typemaps.i %include constraints.i %include exception.i @@ -54,6 +65,7 @@ #ifdef SWIGPYTHON %{ #include "swigutil_py.h" +#include "swigutil_py3c.h" %} #endif #ifdef SWIGPERL @@ -135,9 +147,8 @@ static PyObject * _global_py_pool = NULL /* Python format specifiers. Use Python instead of SWIG to parse these basic types, because Python reports better error messages (with correct argument numbers). */ -%typemap (in, parse="s") - char *, char const *, char * const, char const * const ""; %typemap (in, parse="c") char ""; + %typemap (in, fragment=SWIG_As_frag(long)) long { $1 = ($1_ltype)SWIG_As(long)($input); @@ -236,3 +247,40 @@ static VALUE *_global_vresult_address = /* Now, include the main Subversion typemap library. */ %include svn_types.swg %include proxy.swg + + +#ifdef SWIGPYTHON +/* Since Python 3.8+ on Windows, DLL dependencies when loading *.pyd file + * searches only the system paths, the directory containing the *.pyd file and + * the directories added with os.add_dll_directory(). + * See also https://bugs.python.org/issue36085. + */ +%define SVN_PYTHON_MODULEIMPORT +" +def _dll_paths(): + import os + if hasattr(os, 'add_dll_directory'): # Python 3.8+ on Windows + cookies = [] + for path in os.environ.get('PATH', '').split(os.pathsep): + if path and os.path.isabs(path): + try: + cookie = os.add_dll_directory(path) + except OSError: + continue + else: + cookies.append(cookie) + return cookies + else: + return () + +_dll_paths = _dll_paths() +try: + from . import $module +finally: + _dll_path = None + for _dll_path in _dll_paths: + _dll_path.close() + del _dll_paths, _dll_path +" +%enddef +#endif Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_string.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_string.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_string.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_string.swg Fri Jan 14 14:01:45 2022 @@ -36,9 +36,8 @@ typedef struct svn_string_t svn_string_t if (*$1 == NULL) { Py_INCREF(Py_None); s = Py_None; - } - else { - s = PyString_FromStringAndSize((*$1)->data, (*$1)->len); + } else { + s = PyBytes_FromStringAndSize((*$1)->data, (*$1)->len); if (s == NULL) SWIG_fail; } @@ -75,14 +74,33 @@ typedef struct svn_string_t svn_string_t #ifdef SWIGPYTHON %typemap(in) svn_stringbuf_t * { - if (!PyString_Check($input)) { - PyErr_SetString(PyExc_TypeError, "not a string"); - SWIG_fail; - } - $1 = svn_stringbuf_ncreate(PyString_AS_STRING($input), - PyString_GET_SIZE($input), - /* ### gah... what pool to use? */ - _global_pool); + if ($input == Py_None) { + $1 = NULL; + } + else { + Py_ssize_t strBufLen; + char *strBufChar; + if (PyBytes_Check($input)) { + if (-1 == PyBytes_AsStringAndSize($input, &strBufChar, + &strBufLen)) { + SWIG_fail; + } + } + else if (PyUnicode_Check($input)) { + strBufChar = (char *)PyStr_AsUTF8AndSize($input, &strBufLen); + if (PyErr_Occurred()) { + SWIG_fail; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "not a bytes, str or None object"); + SWIG_fail; + } + $1 = svn_stringbuf_ncreate((const char *)strBufChar, strBufLen, + /* ### gah... what pool to use? */ + _global_pool); + } } #endif @@ -139,7 +157,7 @@ typedef struct svn_string_t svn_string_t #ifdef SWIGPYTHON %typemap(out) svn_stringbuf_t * { - $result = PyString_FromStringAndSize($1->data, $1->len); + $result = PyBytes_FromStringAndSize($1->data, (Py_ssize_t)($1->len)); } #endif @@ -171,15 +189,29 @@ typedef struct svn_string_t svn_string_t /* const svn_string_t * is always an input parameter */ #ifdef SWIGPYTHON %typemap(in) const svn_string_t * (svn_string_t value) { - if ($input == Py_None) + if ($input == Py_None) { $1 = NULL; + } else { - if (!PyString_Check($input)) { - PyErr_SetString(PyExc_TypeError, "not a string"); + Py_ssize_t pyStrLen; + if (PyBytes_Check($input)) { + if (PyBytes_AsStringAndSize($input, (char **)&(value.data), + &pyStrLen) == -1) { + SWIG_fail; + } + } + else if (PyUnicode_Check($input)) { + value.data = PyStr_AsUTF8AndSize($input, &pyStrLen); + if ((value.data == NULL) || PyErr_Occurred()) { + SWIG_fail; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "not a bytes, str, or None object"); SWIG_fail; } - value.data = PyString_AS_STRING($input); - value.len = PyString_GET_SIZE($input); + value.len = pyStrLen; $1 = &value; } } @@ -223,7 +255,7 @@ typedef struct svn_string_t svn_string_t #ifdef SWIGPYTHON %typemap(out) svn_string_t * { - $result = PyString_FromStringAndSize($1->data, $1->len); + $result = PyBytes_FromStringAndSize($1->data, $1->len); } #endif #ifdef SWIGPERL @@ -242,6 +274,26 @@ typedef struct svn_string_t svn_string_t } #endif + /* ----------------------------------------------------------------------- + Type: char * (input) +*/ +#ifdef SWIGPYTHON +%typemap (in) IN_STRING +{ + $1 = svn_swig_py_string_to_cstring($input, FALSE, "$symname", "$1_name"); + if (PyErr_Occurred()) SWIG_fail; +} + +%typemap (freearg) IN_STRING ""; + +%apply IN_STRING { + const char *, + char *, + char const *, + char * const, + char const * const +}; +#endif /* ----------------------------------------------------------------------- define a way to return a 'const char *' */ @@ -253,7 +305,7 @@ typedef struct svn_string_t svn_string_t s = Py_None; } else { - s = PyString_FromString(*$1); + s = PyBytes_FromString(*$1); if (s == NULL) SWIG_fail; } @@ -283,4 +335,8 @@ typedef struct svn_string_t svn_string_t #endif /* svn_wc_get_ancestry() lacks a 'const' */ -%apply const char **OUTPUT { const char **, char **url }; +%apply const char **OUTPUT { + const char **, + char **url, + char **log_message +}; Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_swigcompat.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_swigcompat.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_swigcompat.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_swigcompat.swg Fri Jan 14 14:01:45 2022 @@ -45,7 +45,7 @@ #if SWIG_VERSION <= 0x010327 #ifdef SWIGPYTHON %define %set_constant(name, value) -PyDict_SetItemString(d, name, value); +PyDict_SetItem(d, PyBytes_FromString(name), value); %enddef #endif #endif Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_types.swg URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_types.swg?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_types.swg (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/include/svn_types.swg Fri Jan 14 14:01:45 2022 @@ -93,6 +93,7 @@ %apply SWIGTYPE **OUTPARAM { /* apr */ apr_file_t **, + apr_hash_t **, /* svn_types.h */ svn_commit_info_t **, svn_dirent_t **, @@ -116,10 +117,16 @@ void **credentials, void **iter_baton, void **token, + /* svn_checksum */ + svn_checksum_t **, /* svn_client */ svn_client_commit_info_t **, + svn_client_conflict_t **, + svn_client_conflict_option_t **, svn_client_ctx_t **, const svn_client_commit_item3_t **, + svn_client__shelf_t **, + svn_client__shelf_version_t **, /* svn_delta */ const svn_delta_editor_t **, svn_txdelta_stream_t **, @@ -129,6 +136,7 @@ svn_txdelta_window_handler_t *, #endif void **handler_baton, + void **handler2_baton, void **root_baton, void **child_baton, void **file_baton, @@ -142,6 +150,9 @@ svn_fs_root_t **, svn_fs_txn_t **, void **contents_baton_p, + /* svn_io */ + svn_io_dirent2_t **, + svn_stream_mark_t **, /* svn_ra */ svn_ra_callbacks2_t **, svn_ra_plugin_t **, @@ -335,7 +346,11 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se Create a typemap for specifying string args that may be NULL. */ #ifdef SWIGPYTHON -%typemap(in, parse="z") const char *MAY_BE_NULL ""; +%typemap(in) const char *MAY_BE_NULL +{ + $1 = svn_swig_py_string_to_cstring($input, TRUE, "$symname", "$1_name"); + if (PyErr_Occurred()) SWIG_fail; +} #endif #ifdef SWIGPERL @@ -423,6 +438,55 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se Py_INCREF(Py_None); $result = Py_None; } + +%typemap(out) svn_error_t * SVN_ERR_WITH_ATTRS (apr_status_t apr_err, + PyObject *exc_class, + PyObject *exc_ob) { + apr_err = 0; + exc_class = exc_ob = NULL; + if ($1 != NULL) + { + apr_err = $1->apr_err; + if (apr_err != SVN_ERR_SWIG_PY_EXCEPTION_SET) + { + svn_swig_py_build_svn_exception(&exc_class, &exc_ob, $1); + if (exc_ob == NULL) + { + /* We couldn't get an exception instance. */ + if (exc_class != NULL) + { + /* Raise an exception without instance ... */ + PyErr_SetNone(exc_class); + Py_DECREF(exc_class); + } + SWIG_fail; + } + /* We have an exeception instance, but we don't raise it until + typemap(ret) block after typemap(argout) blocks. */ + } + else + { + svn_error_clear($1); + SWIG_fail; + } + } + else + { + Py_INCREF(Py_None); + $result = Py_None; + } +} + +%typemap(ret) svn_error_t * SVN_ERR_WITH_ATTRS { + if (exc_ob != NULL) + { + PyErr_SetObject(exc_class, exc_ob); + Py_DECREF(exc_class); + Py_DECREF(exc_ob); + Py_XDECREF($result); + SWIG_fail; + } +} #endif #ifdef SWIGPERL @@ -464,12 +528,23 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se */ #ifdef SWIGPYTHON %typemap(in) (const char *PTR, apr_size_t LEN) { - if (!PyString_Check($input)) { - PyErr_SetString(PyExc_TypeError, "expecting a string"); + Py_ssize_t pyStrLen; + if (PyBytes_Check($input)) { + if (PyBytes_AsStringAndSize($input, (char **)&$1, &pyStrLen) == -1) { + SWIG_fail; + } + } + else if (PyUnicode_Check($input)) { + $1 = (char *)PyStr_AsUTF8AndSize($input, &pyStrLen); + if (PyErr_Occurred()) { + SWIG_fail; + } + } + else { + PyErr_SetString(PyExc_TypeError, "expecting a bytes or str"); SWIG_fail; } - $1 = PyString_AS_STRING($input); - $2 = PyString_GET_SIZE($input); + $2 = pyStrLen; } #endif @@ -941,7 +1016,15 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se #ifdef SWIGPYTHON %typemap(in) svn_stream_t *WRAPPED_STREAM { - $1 = svn_swig_py_make_stream ($input, _global_pool); + if ($input == Py_None) { + $1 = NULL; + } + else { + $1 = svn_swig_py_make_stream ($input, _global_pool); + if ($1 == NULL) { + SWIG_fail; + } + } } #endif @@ -1094,7 +1177,7 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se #ifdef SWIGPYTHON %typemap(argout) unsigned char digest[ANY] { - %append_output(PyString_FromStringAndSize((char *)$1, APR_MD5_DIGESTSIZE)); + %append_output(PyBytes_FromStringAndSize((const char *)$1, APR_MD5_DIGESTSIZE)); } #endif @@ -1167,7 +1250,7 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se if ($input == Py_None) { $1 = NULL; } else { - $1 = (unsigned char *) PyString_AsString($input); + $1 = (unsigned char *) PyBytes_AsString($input); if ($1 == NULL) SWIG_fail; } } Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c Fri Jan 14 14:01:45 2022 @@ -284,7 +284,7 @@ apr_array_header_t *svn_swig_pl_objs_to_ /* Convert a single revision range or an array of revisions ranges * Note: We can't simply use svn_swig_pl_to_array() as is, since - * it immediatley checks whether source is an array reference and then + * it immediately checks whether source is an array reference and then * proceeds to treat this as the "array of ..." case. But a revision range * may be specified as a (two-element) array. Hence we first try to * convert source as a single revision range. Failing that and if it's @@ -591,7 +591,7 @@ svn_error_t *svn_swig_pl_callback_thunk( case 'L': /* apr_int64_t */ /* Pass into perl as a string because some implementations may * not be able to handle a 64-bit int. If it's too long to - * fit in Perl's interal IV size then perl will only make + * fit in Perl's internal IV size then perl will only make * it available as a string. If not then perl will convert * it to an IV for us. So this handles the problem gracefully */ c = malloc(30); @@ -634,7 +634,7 @@ svn_error_t *svn_swig_pl_callback_thunk( count = call_method(func, call_flags ); break; default: - croak("unkonwn calling type"); + croak("unknown calling type"); break; } SPAGAIN ; Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Client.pm URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Client.pm?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Client.pm (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Client.pm Fri Jan 14 14:01:45 2022 @@ -1029,7 +1029,7 @@ is updated. If $ignore_externals is set, don't process externals definitions as part of this operation. -If $depth is $SVN::Depth::infinity, update fully recursivelly. Else if it is +If $depth is $SVN::Depth::infinity, update fully recursively. Else if it is $SVN::Depth::immediates or $SVN::Depth::files, update each target and its file entries, but not its subdirectories. Else if $SVN::Depth::empty, update exactly each target, nonrecursively (essentially, update the target's Modified: subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Core.pm URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Core.pm?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Core.pm (original) +++ subversion/branches/multi-wc-format/subversion/bindings/swig/perl/native/Core.pm Fri Jan 14 14:01:45 2022 @@ -784,7 +784,7 @@ $SVN::Depth::infinity. Exclude (i.e., don't descend into) directory D. -Note: In Subversion 1.5, $SVN::Depth::exclude is B<not> supported anyhwere in +Note: In Subversion 1.5, $SVN::Depth::exclude is B<not> supported anywhere in the client-side (Wc/Client/etc) code; it is only supported as an argument to set_path functions in the Ra and Repos reporters. (This will enable future versions of Subversion to run updates, etc, against 1.5 servers with proper Propchange: subversion/branches/multi-wc-format/subversion/bindings/swig/python/ ------------------------------------------------------------------------------ --- svn:ignore (original) +++ svn:ignore Fri Jan 14 14:01:45 2022 @@ -1,5 +1,6 @@ *.pyc *.py +__pycache__ *.c *.la *.lo
