Update Subversion to 1.14.0 LTS. See contrib/subversion/CHANGES for a

summary of changes, or for a more thorough overview:

https://subversion.apache.org/docs/release-notes/1.14

NOTE: there is no need to dump and reload repositories, and the working
copy format is still the same as Subversion 1.8 through 1.13.

Relnotes:	yes
MFC after:	2 weeks
X-MFC-With:	r361677
This commit is contained in:
Dimitry Andric 2020-06-01 10:27:05 +00:00
commit b7ec5dea64
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=361693
296 changed files with 35237 additions and 18619 deletions

View File

@ -7,3 +7,13 @@ indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = false
[**/Makefile*]
indent_style = tab
[build-outputs.mk]
indent_style = tab
[build/generator/templates/build-outputs.mk.ezt]
indent_style = tab

View File

View File

View File

View File

@ -1,5 +1,355 @@
# To view a revision listed as (rXXXXXXX), visit:
# https://svn.apache.org/rXXXXXXX
#
# To view an issue listed as (issue #XXXX), visit:
# https://subversion.apache.org/issue-XXXX
Version 1.14.0
(6 May 2020, from /branches/1.14.x)
https://svn.apache.org/repos/asf/subversion/tags/1.14.0
User-visible changes:
- Minor new features and improvements:
* Experimental shelving feature is now disabled by default (r1875039)
* Reinstate support for experimental shelving v2 from SVN 1.11 (r1875037)
* Introduce 'svnadmin build-repcache' command (r1875921 et al)
- Client-side improvements and bugfixes:
* Add 'changelist' option to 'svn info --show-item' (r1869481)
* Allow simultaneous use of 'svn log' --quiet and --diff options (r1871916)
* Fix 'svn info' for file that was inside replaced directory (issue #4837)
* Don't abort if the server redirects to a non-canonical URL (r1873375)
* Fix merge assertion failure in svn_sort__array_insert (issue #4840)
* Escape filenames when invoking $SVN_EDITOR (r1874057 et al)
* Small performance optimization for FSFS rep-cache.db (r1875918)
* Fix a crash seen when using git-svn with kwallet (r1875680)
- Server-side improvements and bugfixes:
* Fix 'svnadmin load --normalize-props' for versioned properties (r1868203)
* mailer.py: prevent SMTP errors from impeding later emails (issue #1804)
* mailer.py: Add option to specify the SMTP port to connect to (r1872398)
* Make svn-backup-dump.py work on Python 3
* validate-files.py: Fix handling for non-ASCII characters (r1874393)
* Fix an undefined behavior problem in FSFS caching code (r1876054)
Developer-visible changes:
* Require at least version 1.5 of APR (r1874094)
* Support Python3 in the py-swig bindings; requires py3c (r1869354 et al)
* Support building with SWIG 4 on Python 3.x (r1869853)
* Fix svnserveautocheck for Python 3 (r1868151)
* contribulyze.py: Support Python 3 in addition to Python 2 (r1871211)
* Fix Proc.new warnings in Ruby bindings with Ruby >= 2.7 (r1876020)
Version 1.13.0
(30 Oct 2019, from /branches/1.13.x)
https://svn.apache.org/repos/asf/subversion/tags/1.13.0
User-visible changes:
- Minor new features and improvements:
* New 'svnadmin rev-size' command to report revision size (r1857624)
* In 'svn help', hide experimental commands and global options (issue #4828)
* Add a hint about mod_dav_svn misconfiguration (r1866738)
* Performance improvement for 'svn st' etc., in WC SQLite DB (r1865523)
- Client-side bugfixes:
* Windows: avoid delays in SSL certificate validation override (r1863018)
* Fix 'svn patch' setting mode 0600 on patched files with props (r1864440)
* Fix "svn diff --changelist ARG" broken in subdirectories (issue #4822)
* Fix misleading 'redirect cycle' error on a non-repository URL (r1866899)
- Server-side bugfixes:
* svnserve: Report some errors that we previously ignored (r1866062)
* Make server code more resilient to malformed paths and URLs (r1866318 et al)
* Make dump stream parser more resilient to malformed dump stream (r1866951)
* mod_dav_svn: Fix missing Last-Modified header on 'external' GET requests (r1866425)
- Client-side and server-side bugfixes:
* Fix excessive memory usage in some cases reading binary data (r1866950)
* Win32: fix svn_io_file_rename2() spinning in a retry loop (r1865518)
- Other tool improvements and bugfixes:
* svn_load_dirs.pl: do not show password; fix cleanup (r1863262, r1863392)
Developer-visible changes:
* New svn_fs_ioctl() API for FSFS stats, dump/load index, rev-size (r1857435)
Version 1.12.2
(24 Jul 2019, from /branches/1.12.x)
https://svn.apache.org/repos/asf/subversion/tags/1.12.2
User-visible changes:
* Fix conflict resolver bug: local and incoming edits swapped. (r1863285)
* Fix memory lifetime problem in a libsvn_wc error code path. (r1863287)
* Faster Windows file existence checks, improving 'svn st' etc. (r1863289)
Developer-visible changes:
* Allow generating Visual Studio 2019 projects (r1863286)
* Fix build with APR 1.7.0. (r1860377)
* Fix building Subversion with Visual Studio 2005 and 2008. (r1863288)
* Allow svnserve's 'get-deleted-rev' API to return 'not deleted'. (r1863290)
Version 1.12.1
(Not released; see changes for 1.12.2.)
Version 1.12.0
(12 Apr 2019, from /branches/1.12.x)
https://svn.apache.org/repos/asf/subversion/tags/1.12.0
User-visible changes:
- Major new features:
- Minor new features and improvements:
* 'move vs. move' merge conflicts can now be resolved (r1846851, r1851913)
* 'svn --version --verbose' shows loaded libraries on Linux (r1843774)
* 'svnrdump' can read/write a file instead of stdin/stdout (r1844906)
* 'svn list' tries to not truncate the author's name (r1847384 et al.)
* 'svn list' can show sizes in base-2 unit suffixes (r1847384 et al.)
* 'svn info' shows the size of files in the repository (r1847441 et al.)
* 'svn cleanup' can remove read-only directories (#4806, r1854072 et al.)
- Client-side bugfixes:
* Repos-to-WC copy with --parents works with absent target (r1843888)
* Repos-to-WC copy from foreign repo with peg/operative revs (#4785)
- Server-side bugfixes:
* Ignore empty group definitions in authz files (#4802, r1851687)
- Client-side and server-side bugfixes:
- Other tool improvements and bugfixes:
* svnauthz: warn about empty groups in authz files (#4803, r1851823)
* Storing passwords in plain text on disk is disabled by default (r1845377)
Developer-visible changes:
- General:
* Updated the required libtool version to 2.x (r1845716)
* get-deps.sh: Remove references to Googlemock and Googletest (r1849200)
* All C++ code is compiled in C++11 mode by default (r1849202)
- Bindings:
* JavaHL: Fixed potential core dump in ISVNClient.diff (r1845408)
* JavaHL: Let clients decode file contents from ISVNClient.blame (r1851333)
Version 1.11.1
(11 Jan 2019, from /branches/1.11.x)
http://svn.apache.org/repos/asf/subversion/tags/1.11.1
User-visible changes:
- Minor new features and improvements:
* Conflict resolver support for added vs unversioned file (r1845577)
* Conflict resolver support for unversioned directories (r1846299)
* Improve help for 'svn add' and the '-N' option (r1842814 et al.)
* Improve display of Mac OS name in 'svn --version --verbose' (r1842334)
- Client-side bugfixes:
* Fix: repos-to-WC copy with --parents doesn't create dirs (#4768)
* Fix: foreign repo copy with peg/operative revisions (#4785)
* Fix: foreign repo copy of file adding mergeinfo (#4792)
* Fix: assertion failure using -rPREV on a working copy at r0 (#4532)
* Fix: tree conflict message ends a sentence with a colon (#4717)
- Server-side bugfixes:
* Fix CVE-2018-11803: malicious SVN clients can crash mod_dav_svn
* Fix: unexpected SVN_ERR_FS_NOT_DIRECTORY errors (#4791)
* Fix: mod_dav_svn's SVNUseUTF8 had no effect in some setups (r1844882)
* Fix crash in mod_http2 (#4782)
- Other tool improvements and bugfixes:
* svndumpfilter: Clarify error messages by including node path (r1845261)
- Bindings bugfixes:
* JavaHL: Fix crash in client code when using external diff (r1845408)
Developer-visible changes:
- General:
* Fix build on systems without python in $PATH (r1845555)
* Fix compiler warnings about indentation (r1845556 et al.)
- API changes:
(none)
Version 1.11.0
(30 Oct 2018, from /branches/1.11.x)
http://svn.apache.org/repos/asf/subversion/tags/1.11.0
User-visible changes:
- Major new features:
* Shelving is no longer based on patch files (experimental) (issue #3625)
* Checkpointing (experimental) (issue #3626)
* Viewspec output command (experimental) (issue #4753)
- Minor new features and improvements:
* Improvements to tree conflict resolution (issue #4694 #4766 ...)
* 'patch' can now read non-pretty-printed svn:mergeinfo diffs (r1822151)
* Better error when http:// URL is not a Subversion repository (r1825302)
* Add 'schedule' and 'depth' items to 'svn info --show-item' (r1827032)
* Allow the client cert password to be saved (r1836762)
- Client-side bugfixes:
* Fix a crash in a repo:WC summary diff of a local copy (r1835218)
* Fix double diff headers (r1836746)
* Tree conflict resolver: avoid endless scan in some cases (r1839662)
- Server-side bugfixes:
* svnadmin dump shouldn't canonicalize svn:date (issue #4767)
* 'svnadmin verify --keep-going --quiet' shows an error summary (r1837790)
* Let 'svnadmin recover' prune the rep-cache even if disabled (r1838813)
- Client-side and server-side bugfixes:
* Fix pattern-matching of top level path in listing with search (r1830599)
* Allow commands like 'svn ci --file X' to work when X is a FIFO (r1836306)
- Other tool improvements and bugfixes:
* tools/client-side/bash_completion: Add '--password-from-stdin' (r1820045)
Developer-visible changes:
- General:
* new tool: tools/dist/edit-N-log-messages (r1819207)
* tools/dev/unix-build/Makefile.svn: various fixes
* Expose the diff option 'pretty_print_mergeinfo' in APIs (r1822014)
* In 'revert' APIs, choose whether to delete schedule-add nodes (r1822534)
- Bindings:
* Fix Python binding fs.FileDiff behaviour with python-future (r1823802)
* Fix Python unit test, fs.SubversionFSTestCase, on Windows (r1824410)
* Bump minimum JDK version required for JavaHL to 1.8 (r1831895)
* Enable building against Java 10 (r1841180 et al)
* Fix a potential crash in JavaHL (issue #4764)
Version 1.10.6
(24 Jul 2019, from /branches/1.10.x)
https://svn.apache.org/repos/asf/subversion/tags/1.10.6
User-visible changes:
* Allow the use of empty groups in authz rules. (r1854883)
* Fix conflict resolver case with move vs move conflicts. (r1863297)
* Fix #4760: Missing children in svnadmin dump --include/exclude. (r1863298)
* Fix #4793: authz rights from inverted access selectors. (r1854882)
* Fix conflict resolver bug: local and incoming edits swapped. (r1863300)
* Fix #4806: Remove on-disk trees with read-only dirs. (r1863299)
* Fix memory lifetime problem in a libsvn_wc error code path. (r1863302)
* No tree conflict when 'svn up' deletes unmodified dir with unversioned items. (r1863296)
* Remove a useless common ancestor search from conflict resolver. (r1863294)
Developer-visible changes:
* Allow generating Visual Studio 2019 projects (r1863304)
* Fix a use-after-free in mod_dav_svn's logging of FS warnings. (r1863292)
* Fix "unused static function" warning in release-mode builds. (r1854884)
* Fix build with APR 1.7.0. (r1863303)
* Fix issue #4804: spurious SQLite-related test failures. (r1863295)
* Allow svnserve's 'get-deleted-rev' API to return 'not deleted'. (r1863305)
* Silence a deprecation warning from amalgamated SQLite on macOS. (r1863291)
Version 1.10.5
(Not released; see changes for 1.10.6.)
Version 1.10.4
(11 Jan 2019, from /branches/1.10.x)
http://svn.apache.org/repos/asf/subversion/tags/1.10.4
User-visible changes:
- Minor new features and improvements:
* Conflict resolver support for added vs unversioned file (r1845577)
* Conflict resolver support for unversioned directories (r1846299)
- Client-side bugfixes:
* Fix: repos-to-WC copy with --parents doesn't create dirs (#4768)
* Fix: foreign repo copy with peg/operative revisions (#4785)
* Fix: foreign repo copy of file adding mergeinfo (#4792)
* Fix: assertion failure using -rPREV on a working copy at r0 (#4532)
* Fix: tree conflict message ends a sentence with a colon (#4717)
- Server-side bugfixes:
* Fix CVE-2018-11803: malicious SVN clients can crash mod_dav_svn
* Fix: unexpected SVN_ERR_FS_NOT_DIRECTORY errors (#4791)
* Fix: mod_dav_svn's SVNUseUTF8 had no effect in some setups (r1844882)
* Fix crash in mod_http2 (#4782)
- Other tool improvements and bugfixes:
* svndumpfilter: Clarify error messages by including node path (r1845261)
- Bindings bugfixes:
* JavaHL: Fix crash in client code when using external diff (r1845408)
Developer-visible changes:
- General:
* Fix build on systems without python in $PATH (r1845555)
- API changes:
(none)
Version 1.10.3
(10 Oct 2018, from /branches/1.10.x)
http://svn.apache.org/repos/asf/subversion/tags/1.10.3
User-visible changes:
- Minor new features and improvements:
* Store the HTTPS client cert password (r1842578)
- Client-side bugfixes:
* Fix shelving when custom diff command is configured (issue #4758)
* Fix conflict resolver crashes (issue #4744, r1842581, r1842582, r1842583)
* Fix conflict resolver endless scan in some cases (r1842586)
* Fix "Accept incoming deletion" on locally deleted file (issue #4739)
* Fix "resolver adds unrelated moves to move target list" (issue #4766)
- Server-side bugfixes:
* Reject bad PUT before CHECKOUT in v1 HTTP protocol (r1841281)
* Let 'svnadmin recover' prune the rep-cache even if disabled (r1842585)
- Client-side and server-side bugfixes:
* Allow commands like 'svn ci --file X' to work when X is a FIFO (r1841282)
- Other tool improvements and bugfixes:
* 'svnadmin verify --keep-going --quiet' shows an error summary (r1842584)
* Fix error in german translation for 'svn help merge' (r1837038)
Developer-visible changes:
- General:
* Python tests use the current python executable (r1842626)
Version 1.10.2
(20 Jul 2018, from /branches/1.10.x)
http://svn.apache.org/repos/asf/subversion/tags/1.10.2
User-visible changes:
- Client-side bugfixes:
* Correctly claim to offer Gnome Keyring support with libsecret (r1831142)
* Fix segfault using Gnome Keyring with libsecret (r1835782)
* Fix JavaHL local refs capacity warning when unparsing externals (r1831143)
* Since on Windows Subversion does not handle symlinks, never check for reparse points (r1835701)
* Prune externals after 'update --set-depth=exclude' (r1835702)
* Fix issue #4740, "conflict resolver searches too far back ..." (r1835703)
- Server-side bugfixes:
* Fix regression issue #4741: authz group refers to multiple groups (r1831220)
Developer-visible changes:
- General:
* Regression test and FSFS checksum test, part of issue #4722 (r1828043)
* Explicit error on configure --without-lz4 or --without-utf8proc (r1831604)
* configure.ac: Fix regression relating to path to 'rdoc' (r1833486)
* Ensure consistent use of $PYTHON during build and test (r1833487)
* Fix libsvn_auth_gnome_keyring.pc when built using libsecret (r1835781)
- Bindings:
* Fix regression in use of pre-generated Swig bindings in release builds (r1833488)
Version 1.10.1
(Not released; see changes for 1.10.2.)
Version 1.10.0
(?? ??? 2018, from /branches/1.10.x)
(13 Apr 2018, from /branches/1.10.x)
http://svn.apache.org/repos/asf/subversion/tags/1.10.0
See the 1.10 release notes for a more verbose overview of the changes since
@ -8,7 +358,7 @@ the 1.9 release: https://subversion.apache.org/docs/release-notes/1.10.html
User-visible changes:
- Major new features:
* Better interactive conflict resolution for tree conflicts (r1687489 et al)
* Wilcards and improved performance in path-based authorization (r1776832)
* Wildcards and improved performance in path-based authorization (r1776832)
* New experimental 'svn shelve' command (issue #3625)
- Minor new features and improvements:
* svnbench: Show time taken & bytes transferred (r1703383, r1710586)
@ -29,7 +379,7 @@ the 1.9 release: https://subversion.apache.org/docs/release-notes/1.10.html
* ra_serf: Adjustments for serf versions with HTTP/2 support (r1716400)
* ra_serf: Send svndiff1 deltas during commit (r1704317, r1704613, r1791290)
* ra_serf: Stream svndiff deltas w/o creating temporary files (r1803143 et al)
* ra_serf: Don't necessarily request full MERGE reponses (r1806017 et al)
* ra_serf: Don't necessarily request full MERGE responses (r1806017 et al)
* 'svn patch': Parse binary diffs in git-style patches (r1703925)
* 'svnadmin info' now reports latest revision in the repository (r1697953)
* ra_svn: Various performance-related tweaks (r1694490)
@ -286,6 +636,102 @@ the 1.9 release: https://subversion.apache.org/docs/release-notes/1.10.html
* Ruby: Detect versions up to 2.4 (r1806570)
Version 1.9.12
(24 Jul 2019, from /branches/1.9.x)
https://svn.apache.org/repos/asf/subversion/tags/1.9.12
User-visible changes:
* No tree conflict when 'svn up' deletes unmodified dir with unversioned items. (r1863309)
Developer-visible changes:
* Allow generating Visual Studio 2019 projects (r1863311)
* Fix a use-after-free in mod_dav_svn's logging of FS warnings. (r1863307)
* Fix "unused static function" warning in release-mode builds. (r1854881)
* Fix build with APR 1.7.0. (r1863310)
* Fix issue #4804: spurious SQLite-related test failures. (r1863308)
* Allow svnserve's 'get-deleted-rev' API to return 'not deleted'. (r1863312)
* Silence a deprecation warning from amalgamated SQLite on macOS. (r1863306)
Version 1.9.11
(Not released; see changes for 1.9.12.)
Version 1.9.10
(11 Jan 2019, from /branches/1.9.x)
http://svn.apache.org/repos/asf/subversion/tags/1.9.10
User-visible changes:
- Client-side bugfixes:
* Fix: repos-to-WC copy with --parents doesn't create dirs (#4768)
* Fix: foreign repo copy with peg/operative revisions (#4785)
* Fix: assertion failure using -rPREV on a working copy at r0 (#4532)
* Fix: german translation for 'svn help merge' (r1837037)
* Fix: prune externals after 'update --set-depth=exclude' (r1830883 et al.)
* Fix: detection of GPG-agent (r1794166 et al.)
* Fix: null updates don't update last-changed-revision (#4700)
* Fix: merge "Unable to parse reversed revision range" (#4686)
- Server-side bugfixes:
* Fix: unexpected SVN_ERR_FS_NOT_DIRECTORY errors (#4791)
* Fix: mod_dav_svn's SVNUseUTF8 had no effect in some setups (r1844882)
* Fix: crash in mod_http2 (#4782)
* Fix: 'svnadmin upgrade' of BDB: Error out on too-new formats (r1804013)
* Fix: Enforce v1 HTTP protocol: error if PUT before CHECKOUT (r1833465)
* Fix: Let 'svnadmin recover' prune rep-cache even if disabled (r1838813)
* Add test and FSFS checksum verification for issue #4722 (r1826720 et al.)
- Other tool improvements and bugfixes:
* Install 'fsfs-stats' wrapper for 1.8 compat (r1802032 et al.)
* Note that 'tools/client-side/detach.py' doesn't work on 1.8+ (r1696722)
- Bindings bugfixes:
* JavaHL: Fix crash in client code when using external diff (r1845408)
* JavaHL: SSL server trust prompt: allow accepting temporarily (r1820718)
Developer-visible changes:
- General:
(none)
- API changes:
(none)
Version 1.9.9
(20 Jul 2018, from /branches/1.9.x)
http://svn.apache.org/repos/asf/subversion/tags/1.9.9
User-visible changes:
- Client-side bugfixes:
* Fix SEGV for 'svn export -rN WC' with relative externals (r1803755)
* Fix issue #4677: 'svn up' after a directory replaced a file (r1814248)
* Fix segfault when no home directory is available (r1819199)
* Performance: Make 'svn info' fast on old repository revisions (r1827690)
* Fix RA-serf problem with proxy username and password (r1833571)
- Server-side bugfixes:
* svnadmin: Fix false errors on some valid LOCK_PATH arguments (r1803754)
* Fix crash when exiting 'svnserve --config-file' (r1824405)
* Fix issue #4722: false "filesystem is corrupt" error on commit (r1827688)
* Reword confusing "nested" wording in an httpd.conf warning (r1835700)
- Bindings bugfixes:
* swig-py: svn.core.Stream supports raw binary file-like objects (r1820620)
* swig-rb: Don't crash if svn_md5_digest_to_cstring returns NULL (r1823805)
Developer-visible changes:
- General:
* Fix CVE-2017-9800: Malicious server can execute arbitrary command on client (r1804698)
* Fix test failure if compile- and run-time HTTPD versions differ (r1820523)
- API changes:
(none)
Version 1.9.8
(Not released; see changes for 1.9.9.)
Version 1.9.7
(10 Aug 2017, from /branches/1.9.x)
http://svn.apache.org/repos/asf/subversion/tags/1.9.7
@ -883,7 +1329,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.0
* cache: fix premature eviction due to 64-bit underflows (r1567996 et al)
* svnserve: fix potential integer overflow in Cyrus SASL support (r1570434)
* bdb: fix potential integer overflow and underflow (r1570701)
* bdb: prevent silent propogation of some corruption (r1570778)
* bdb: prevent silent propagation of some corruption (r1570778)
* svnadmin hotcopy: do not corrupt db/current contents when copying old
FSFS repos (r1603485)
* svnadmin hotcopy: don't produce broken copies when a concurrent pack
@ -1143,7 +1589,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.0
ranges (r1569731)
* svn_rangelist_inheritable2() and svn_mergeinfo_inheritable2(): fix a
pool lifetime issue (r1569764)
* new APIs to support cancelation during unified diff output and
* new APIs to support cancellation during unified diff output and
allow the context size to be specified (r1570149 et al)
* APIs related to retrieving logs are now documented to be unlimited when
a negative value is passed for the limit (r1570330, 1570335)
@ -1261,7 +1707,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.0
* swig-py: Add close to the core.Stream class (r1619077)
* javahl: add example clients that use the authn API (r1640533)
* swig-py: implement dump stream parser (r1642813)
* swig-pl: remove some unneded cleanup code that triggered a cleanup
* swig-pl: remove some unneeded cleanup code that triggered a cleanup
failure on windows (r1643072)
* swig-pl: make cancel_func, cancel_baton parameter pairs work (r1648852)
* javahl: expose whitespace diff parameters to blame method (issue #4475)
@ -1592,7 +2038,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.9
- Client-side bugfixes:
* log: use proper peg revision over DAV (r1568872)
* upgrade: allow upgrading from 1.7 with exclusive locks (r1572102 et al)
* proplist: resolve inconsitent inherited property results (r1575270 et al)
* proplist: resolve inconsistent inherited property results (r1575270 et al)
* increase minimal timestamp sleep from 1ms to 10ms (r1581305 et al)
* merge: automatic merge confused by subtree merge (issue #4481)
* propget: report proper error on invalid revision for url (r1586255)
@ -1634,7 +2080,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.9
Developer-visible changes:
- General:
* improve consistency checks of DAV inherited property requests (r1498000)
* fix ocassional failure in autoprop_tests.py (r1567752)
* fix occasional failure in autoprop_tests.py (r1567752)
* avoid duplicate sqlite analyze information rows (r1571214)
* add Mavericks to our sysinfo output (r1573088)
* bump copyright years to 2014 (r1555403)
@ -1687,7 +2133,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.8
Developer-visible changes:
- General:
* fix ocassional failure of check_tests.py 12 (r1496127 et al)
* fix occasional failure of check_tests.py 12 (r1496127 et al)
* fix failure with SQLite 3.8.1-3.8.3 when built with
SQLITE_ENABLE_STAT3/4 due to bug in SQLite (r1567286, r1567392)
* specify SQLite defaults that can be changed when SQLite is built
@ -1793,7 +2239,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.3
- Client- and server-side bugfixes:
* translation updates for Swedish
* enforce strict version equality between tools and libraries (r1502267)
* consistently output revisions as "r%ld" in error messags (r1499044 et al)
* consistently output revisions as "r%ld" in error messages (r1499044 et al)
- Client-side bugfixes:
* status: always use absolute paths in XML output (issue #4398)
@ -2372,7 +2818,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.7.18
Developer-visible changes:
- General:
* fix ocassional failure in checkout_tests.py test 12. (r1496127)
* fix occasional failure in checkout_tests.py test 12. (r1496127)
* disable building ZLib's assembly optimizations on Windows.
@ -2987,7 +3433,7 @@ the 1.6 release: http://subversion.apache.org/docs/release-notes/1.7.html
* fixed: wc-to-wc copy of a switch source (issue #1802)
* fixed: 'svn st' reports symlinks as obstructed items (issue #2284)
* fixed: 'cd e:\; svn up e:\' fails (issue #2556)
* fixed: svn aborts on commiting from root dir on windows (issue #3346)
* fixed: svn aborts on committing from root dir on windows (issue #3346)
* fixed: removing a dir scheduled for deletion corrupts wc (issue #2741)
* fixed: 'svn cleanup' fails on obstructed paths (issue #2867)
* fixed: case-only renames resulting from merges don't work (issue #3115)
@ -3024,7 +3470,7 @@ the 1.6 release: http://subversion.apache.org/docs/release-notes/1.7.html
* fixed: 'svn info' returns parent info on missing dirs (issue #3178)
* fixed: spurious prop conflict with 'merge --reintegrate' (issue #3919)
* fixed: 'svn --version' fails with non-existent $HOME (issue #3947)
* fixed: unforced export silently overwites existing file (issue #3799)
* fixed: unforced export silently overwrites existing file (issue #3799)
* fixed: reverse merge which adds subtree mergeinfo fails (issue #3978)
* fixed: 'svn up -r{R>HEAD}' hangs client over ra_svn (issue #3963)
* fixed: 'svn up' updates file externals in target siblings (issue #3819)
@ -3368,7 +3814,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.6.11
Developer-visible changes:
* disable checks for wc-ng working copies when running the test suite
* on Windows, don't ignore move operation error codes (r896915)
* more precise reporting of errors occuring with sqlite init (r927323, -8)
* more precise reporting of errors occurring with sqlite init (r927323, -8)
* ensure rangelist APIs are commutative (r923389, -91)
@ -5720,7 +6166,7 @@ http://svn.apache.org/repos/asf/subversion/tags/0.28.2
twice as slow and lose all concurrent-client scalability.
This is a temporary fix for a larger design problem. See issue
http://subversion.tigris.org/issues/show_bug.cgi?id=1499
https://issues.apache.org/jira/browse/SVN-1499
Version 0.28.1
@ -6731,7 +7177,7 @@ Version 0.9 (released 15 Feb 2002, revision 1302)
- no more 'path styles' in path library
- rewrite bootstrapping code for python test framework
- rewrite commandline app's help-system and alias-system
- feedback table replaced with notfication callback
- feedback table replaced with notification callback
- rewrite sorting of hashes
- svnadmin internal rewrite
- faster post-update processing

View File

@ -27,7 +27,7 @@ Blanket commit access:
dlr Daniel Rall <dlr@finemaltcoding.com>
mbk Mark Benedetto King <mbk@lowlatency.com>
jaa Jani Averbach <jaa@iki.fi>
julianfoad Julian Foad <julian@foad.me.uk>
julianfoad Julian Foad <julianfoad@apache.org>
jszakmeister John Szakmeister <john@szakmeister.net>
ehu Erik Hülsmann <ehuels@gmail.com>
breser Ben Reser <ben@reser.org>
@ -61,6 +61,9 @@ Blanket commit access:
astieger Andreas Stieger <andreas.stieger@gmx.de>
jamessan James McCoy <jamessan@jamessan.com>
luke1410 Stefan Hett <luke1410@posteo.de>
troycurtisjr Troy Curtis, Jr <troycurtisjr@gmail.com>
hartmannathan Nathan Hartman <hartman.nathan@gmail.com>
futatuki Yasuhito Futatsuki <futatuki@yf.bsdclub.org>
[[END ACTIVE FULL COMMITTERS. LEAVE THIS LINE HERE; SCRIPTS LOOK FOR IT.]]
@ -87,6 +90,7 @@ Partial committers who have asked to be listed as dormant:
rassilon Bill Tutt <bill@tutts.org> (Win32, COM, issue-1003-dev br.)
pll Paul lussier <p.lussier@comcast.net> (releases)
rdonch Роман Донченко <dpb@corrigendum.ru> (Swig-Python b.)
karolszk Karol Szkudlarek <karol@mikronika.com.pl> (po: pl)
Commit access for specific areas:
@ -103,7 +107,6 @@ Commit access for specific areas:
rschupp Roderich Schupp <roderich.schupp@gmail.com> (Swig bindings)
stilor Alexey Neyman <stilor@att.net> (Python bindings,
svn-vendor.py)
troycurtisjr Troy Curtis, Jr <troycurtisjr@gmail.com> (Swig bindings)
Packages:
@ -179,7 +182,6 @@ Commit access for specific areas:
oyvindmo Øyvind Møll <svn@moll.no> (po: nb)
sunny256 Øyvind A. Holm <sunny@sunbase.org> (po: nb)
jzgoda Jaroslaw Zgoda <jzgoda@o2.pl> (po: pl)
karolszk Karol Szkudlarek <karol@mikronika.com.pl> (po: pl)
plasma Wei-Hon Chen <plasma@ms9.hinet.net> (po: zh_TW)
jihuang June-Yen Huang <jihuang@iis.sinica.edu.tw> (po: zh_TW) [EMAIL
IS BOUNCING]

View File

@ -3,7 +3,7 @@
A Quick Guide
======================================
$LastChangedDate: 2017-12-25 04:00:08 +0000 (Mon, 25 Dec 2017) $
$LastChangedDate: 2020-02-17 03:49:42 +0000 (Mon, 17 Feb 2020) $
Contents:
@ -23,8 +23,8 @@ Contents:
III. BUILDING A SUBVERSION SERVER
A. Setting Up Apache Httpd
B. Making and Installing the Subversion Server
C. Configuring Apache for Subversion
B. Making and Installing the Subversion Apache Server Module
C. Configuring Apache Httpd for Subversion
D. Running and Testing
E. Alternative: 'svnserve' and ra_svn
@ -96,6 +96,11 @@ I. INTRODUCTION
These diff streams are used everywhere -- over the network,
in the repository, and in the client's working copy.
* utf8proc (REQUIRED for client and server)
Subversion uses utf8proc for UTF-8 support, including Unicode
normalization.
* Apache Serf (OPTIONAL for client)
The Apache Serf library allows the Subversion client to send HTTP
@ -116,21 +121,21 @@ I. INTRODUCTION
* Netwide Assembler (OPTIONAL for client and server)
The Netwide Assembler (NASM) is used to build the (optionally)
The Netwide Assembler (NASM) is used to build the (optional)
assembler modules of OpenSSL. As of OpenSSL 1.1.0 NASM is the
only supported assembler.
* Berkeley DB (OPTIONAL for client and server)
* Berkeley DB (DEPRECATED and OPTIONAL for client and server)
There are two different repository 'back-end'
implementations. One implementation stores data in a flat
filesystem (known as FSFS); the other implementation stores
data in a Berkeley DB database (known as BDB). When you
create a repository, you have the option of specifying a
storage back-end. The Berkeley DB back-end will only be
available if the BDB libraries are discovered at compile
time. The Berkeley DB back-end has been deprecated and
is not recommend.
When you create a repository, you have the option of
specifying a storage 'back-end' implementation. Currently,
there are two options. The newer and recommended one, known
as FSFS, does not require Berkeley DB. FSFS stores data in a
flat filesystem. The older implementation, known as BDB, has
been deprecated and is not recommended for new repositories,
but is still available. BDB stores data in a Berkeley DB
database. This back-end will only be available if the BDB
libraries are discovered at compile time.
* libsasl (OPTIONAL for client and server)
@ -147,10 +152,16 @@ I. INTRODUCTION
for other languages, you need to have those languages
available at build time.
* KDELibs, GNOME Keyring (OPTIONAL for client)
* py3c (OPTIONAL, but REQUIRED for Python bindings)
The Python 3 Compatibility Layer for C Extensions is required
to build the Python language bindings.
* KDE Framework 5, libsecret, GNOME Keyring (OPTIONAL for client)
Subversion contains optional support for storing passwords in
KWallet (KDE 4) or GNOME Keyring.
KWallet via KDE Framework 5 libraries (preferred) or kdelibs4,
and GNOME Keyring via libsecret (preferred) or GNOME APIs.
* libmagic (OPTIONAL)
@ -160,10 +171,6 @@ I. INTRODUCTION
configured via auto-props or the mime-types-file option
take precedence.
* Googlemock aka Gmock (OPTIONAL)
This optional package is used by the tests for Subversions'
C++ bindings.
C. Dependencies in Detail
@ -199,7 +206,7 @@ I. INTRODUCTION
commands described in section II.B before installing the following.
1. Apache Portable Runtime 1.3 or newer (REQUIRED)
1. Apache Portable Runtime 1.5 or newer (REQUIRED)
Whenever you want to build any part of Subversion, you need the
Apache Portable Runtime (APR) and the APR Utility (APR-util)
@ -253,22 +260,55 @@ I. INTRODUCTION
configure script.
2. Zlib (REQUIRED)
2. SQLite (REQUIRED)
Subversion's binary-differencing engine depends on zlib for
compression. Most Unix systems have libz pre-installed, but
if you need it, you can get it from
Subversion requires SQLite version 3.8.2 or above. You can meet this
dependency several ways:
* Use an SQLite amalgamation file.
* Specify an SQLite installation to use.
* Let Subversion find an installed SQLite.
http://www.zlib.net/
To use an SQLite-provided amalgamation, just drop sqlite3.c into
Subversion's sqlite-amalgamation/ directory, or point to it with the
--with-sqlite configure option. This file also ships with the Subversion
dependencies distribution, or you can download it from SQLite:
https://www.sqlite.org/download.html
3. autoconf 2.59 or newer (Unix only)
3. Zlib (REQUIRED)
Subversion's binary-differencing engine depends on zlib for
compression. Most Unix systems have libz pre-installed, but if
you need it, you can get it from
http://www.zlib.net/
4. utf8proc (REQUIRED)
Subversion uses utf8proc for UTF-8 support. Configure will
attempt to locate utf8proc by default using pkg-config and known
paths.
If it is installed in a non-standard location, then use:
--with-utf8proc=/path/to/libutf8proc
Alternatively, a copy of utf8proc comes bundled with the
Subversion sources. If configure should use the bundled copy,
use:
--with-utf8proc=internal
5. autoconf 2.59 or newer (Unix only)
This is required only if you plan to build from the latest source
(see section II.B). Generally only developers would be doing this.
4. libtool 1.4 or newer (Unix only)
6. libtool 1.4 or newer (Unix only)
This is required only if you plan to build from the latest source
(see section II.B).
@ -277,7 +317,7 @@ I. INTRODUCTION
newer. The autogen.sh script knows about that.
5. Apache Serf library 1.3.4 or newer (OPTIONAL)
7. Apache Serf library 1.3.4 or newer (OPTIONAL)
If you want your client to be able to speak to an Apache
server (via a http:// or https:// URL), you must link against
@ -292,12 +332,13 @@ I. INTRODUCTION
instead.
Apache Serf can be obtained via your system's package distribution
system or directly from http://code.google.com/p/serf/.
system or directly from https://serf.apache.org/.
For more information on Apache Serf and Subversion's ra_serf, see the
file subversion/libsvn_ra_serf/README.
6. OpenSSL (OPTIONAL)
8. OpenSSL (OPTIONAL)
### needs some updates. I think Apache Serf automagically handles
### finding OpenSSL, but we may need more docco here. and w.r.t
@ -343,17 +384,25 @@ I. INTRODUCTION
https://www.openssl.org/
7. Berkeley DB 4.X (OPTIONAL)
9. Berkeley DB 4.X (DEPRECATED and OPTIONAL)
Berkeley DB is needed to build a Subversion server that supports
the BDB repository filesystem, or to access a BDB repository on
local disk. If you will only use the FSFS repository filesystem,
or if you are building a Subversion client that will only speak
to remote (networked) repositories, you don't need it.
You need the Berkeley DB libraries only if you are building a
Subversion server that supports the older BDB repository storage
back-end, or a Subversion client that can access local BDB
repositories via the file:// URI scheme.
The current recommended version is 4.4.20 or newer, which brings
auto-recovery functionality to the Berkeley DB database
environment.
The BDB back-end has been deprecated and is not recommended for
new repositories. BDB may be removed in Subversion 2.0. We
recommend the newer FSFS back-end for all new repositories.
FSFS does not require the Berkeley DB libraries.
If in doubt, the 'svnadmin info' command, added in Subversion
1.9, can identify whether an existing repository uses BDB or
FSFS.
The current recommended version of Berkeley DB is 4.4.20 or
newer, which brings auto-recovery functionality to the Berkeley
DB database environment.
If you must use an older version of Berkeley DB, we *strongly*
recommend using 4.3 or 4.2 over the 4.1 or 4.0 versions. Not
@ -386,7 +435,7 @@ I. INTRODUCTION
Look in the "Releases > Windows > Windows BDB" section.
8. Cyrus SASL library (OPTIONAL)
10. Cyrus SASL library (OPTIONAL)
If the Simple Authentication and Security Layer (SASL) library
is detected on your system, then the Subversion client and
@ -397,7 +446,7 @@ I. INTRODUCTION
http://freshmeat.net/projects/cyrussasl/
9. Apache Web Server 2.2.X or newer (OPTIONAL)
11. Apache Web Server 2.2.X or newer (OPTIONAL)
(https://httpd.apache.org/download.cgi)
@ -410,78 +459,103 @@ I. INTRODUCTION
is done: See section III for details.
10. Python 2.7 or newer (https://www.python.org/) (OPTIONAL)
12. Python 3.x or newer (https://www.python.org/) (OPTIONAL)
If you want to run "make check" or build from the latest source
under Unix/Windows as described in section II.B, II.E and III.D,
install Python 2.7 or higher on your system. The majority of the
test suite is written in Python, as is part of Subversion's build
system.
Subversion does not require Python for its basic operation.
However, Python is required for building and testing Subversion
and for using Subversion's SWIG Python bindings or hook scripts
coded in Python.
Note that Python 3.x is not supported and most likely won't work.
The majority of Subversion's test suite is written in Python, as
is part of Subversion's build system.
In more detail, Python is required to do any of the following:
* Use the SWIG Python bindings.
* Use the ctypes Python bindings.
* Use hook scripts coded in Python.
* Build Subversion from a tarball on Unix-like systems and run
Subversion's test suite as described in section II.B.
* Build Subversion on Windows as described in section II.E.
* Build Subversion from a working copy checked out from
Subversion's own repository (whether or not running the test
suite).
* Build the SWIG Python bindings.
* Build the ctypes Python bindings.
* Testing as described in section III.D.
The Python bindings are used by:
* Third-party programs (e.g., ViewVC)
* Scripts distributed with Subversion itself in the tools/
subdirectory.
* Any in-house scripts you may have.
Python is NOT required to do any of the following:
* Use the core command-line binaries (svn, svnadmin, svnsync,
etc.)
* Use Subversion's C libraries.
* Use any of Subversion's other language bindings.
* Build Subversion from a tarball on Unix-like systems without
running Subversion's test suite
Although this section calls for Python 3.x, Subversion still
technically works with Python 2.7. However, Support for Python
2.7 is being phased out. As of 1 January 2020, Python 2.7 has
reached end of life. All users are strongly encouraged to move
to Python 3.
11. Perl 5.8 or newer (Windows only) (OPTIONAL)
13. Perl 5.8 or newer (Windows only) (OPTIONAL)
To build Subversion under any of the MS Windows platforms, you
will also need Perl 5.8 or newer to run apr-util's w32locatedb.pl
script.
12. SQLite (REQUIRED)
Subversion requires SQLite version 3.8.2 or above. You can meet this
dependency several ways:
* Use an SQLite amalgamation file.
* Specify an SQLite installation to use.
* Let Subversion find an installed SQLite.
To use an SQLite-provided amalgamation, just drop sqlite3.c into
Subversion's sqlite-amalgamation/ directory, or point to it with the
--with-sqlite configure option. This file also ships with the Subversion
dependencies distribution, or you can download it from SQLite:
https://www.sqlite.org/download.html
13. pkg-config (Unix only, OPTIONAL)
14. pkg-config (Unix only, OPTIONAL)
Subversion uses pkg-config to find appropriate options used
at build time.
14. D-Bus (Unix only, OPTIONAL)
15. D-Bus (Unix only, OPTIONAL)
D-Bus is a message bus system. D-Bus is required for support for KWallet
and GNOME Keyring. pkg-config is needed to find D-Bus headers and library.
15. Qt 4 (Unix only, OPTIONAL)
16. Qt 5 or Qt 4 (Unix only, OPTIONAL)
Qt is a cross-platform application framework. QtCore, QtDBus and QtGui
modules are required for support for KWallet. pkg-config is needed
to find Qt headers and libraries.
16. KDELibs 4 (Unix only, OPTIONAL)
17. KDE 5 Framework libraries or KDELibs 4 (Unix only, OPTIONAL)
Subversion contains optional support for storing passwords in KWallet.
Subversion will look for KF5Wallet, KF5CoreAddons, KF5I18n APIs by default,
and needs kf5-config to find them. The KDELibs 4 api is also supported.
KDELibs contains core KDE libraries. Subversion uses libkdecore and libkdeui
libraries when support for KWallet is enabled. kde4-config is used to get
some necessary options. pkg-config, D-Bus and Qt 4 are also required.
If you want to build support for KWallet, then pass the '--with-kwallet'
option to `configure`. If KDE is installed in a non-standard prefix, then
use:
--with-kwallet=/path/to/KDE/prefix
17. GLib 2 (Unix only, OPTIONAL)
18. GLib 2 (Unix only, OPTIONAL)
GLib is a general-purpose utility library. GLib is required for support
for GNOME Keyring. pkg-config is needed to find GLib headers and library.
18. GNOME Keyring (Unix only, OPTIONAL)
19. GNOME Keyring (Unix only, OPTIONAL)
Subversion contains optional support for storing passwords in GNOME Keyring.
pkg-config is needed to find GNOME Keyring headers and library. D-Bus and
@ -489,7 +563,7 @@ I. INTRODUCTION
then pass the '--with-gnome-keyring' option to `configure`.
19. Ctypesgen (OPTIONAL)
20. Ctypesgen (OPTIONAL)
Ctypesgen is Python wrapper generator for ctypes. It is used to generate
a part of Subversion Ctypes Python bindings (CSVN). If you want to build
@ -500,7 +574,8 @@ I. INTRODUCTION
For more information on CSVN, see subversion/bindings/ctypes-python/README.
20. libmagic (OPTIONAL)
21. libmagic (OPTIONAL)
Subversion's configure script attempts to find libmagic automatically.
If it is installed in a non-standard location, then use:
@ -521,11 +596,6 @@ I. INTRODUCTION
--with-libmagic
21. Googlemock (OPTIONAL)
Googlemock can be installed and built in-tree by invoking
$ ./get-dep.sh gmock
22. LZ4 (OPTIONAL)
@ -540,6 +610,32 @@ I. INTRODUCTION
If configure should use the version bundled with the sources, use:
--with-lz4=internal
23. py3c (OPTIONAL)
Subversion uses the Python 3 Compatibility Layer for C
Extensions (py3c) library when building the Python language
bindings.
As py3c is a header-only library, it is needed only to build the
bindings, not to use them.
Configure will attempt to locate py3c by default using
pkg-config and known paths.
If it is installed in a non-standard location, then use:
--with-py3c=/path/to/py3c/prefix
The library can be downloaded from GitHub:
https://github.com/encukou/py3c
On Unix systems, you can also use the provided get-deps.sh
script to download py3c and several other dependencies; see the
top of section I.C for more about get-deps.sh.
D. Documentation
The primary documentation for Subversion is the free book
@ -731,13 +827,12 @@ II. INSTALLATION
Edition). Make sure you enable C++ support during setup.
* Python 2.7 or higher, downloaded from https://www.python.org/ which is
used to generate the project files.
Note that Python 3.x is not supported (yet).
* Perl 5.8 or higher from https://www.perl.org/get.html
* Awk (from https://www.cs.princeton.edu/~bwk/btl.mirror/awk95.exe) is
needed to compile Apache. Note that this is the actual awk program,
not an installer - just rename it to awk.exe and it is ready to use.
* Apache apr, apr-util, and optionally apr-iconv libraries, version
1.3 or later (1.2 for apr-iconv). If you are building from a Subversion
1.5 or later (1.2 for apr-iconv). If you are building from a Subversion
checkout and have not downloaded Apache 2, then get these 3 libraries
from https://www.apache.org/dist/apr/.
* SQLite 3.8.2 or higher from https://www.sqlite.org/download.html
@ -856,11 +951,7 @@ II. INSTALLATION
E.4 Building the Binaries
To build the binaries either follow the instructions here or use
build\win32\vc6-build.bat.in after editing its default paths to match
yours and saving it as vc6-build.bat. The vc6-build.bat does a full build
using all options so it requires Apache 2 source and the other optional
components.
To build the binaries either follow these instructions.
Start in the SVN directory you created.
@ -922,7 +1013,7 @@ II. INSTALLATION
C:>nmake -f Makefile.win
C:>nmake -f Makefile.win install
Please refere to the build instructions provided by the library source
Please refer to the build instructions provided by the library source
for actual build instructions.
ZLib
@ -931,7 +1022,7 @@ II. INSTALLATION
Building ZLib using Visual Studio should be quite simple. Just open the
appropriate solution and build the project zlibstat using the IDE.
Please refere to the build instructions provided by the library source
Please refer to the build instructions provided by the library source
for actual build instructions.
Note that you'd make sure to define ZLIB_WINAPI in the ZLib config

View File

@ -423,3 +423,24 @@ For the (modified) LZ4 library files in subversion/libsvn_subr/lz4
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
For the Autoconf Archive macros for Boost:
* in build/ac-macros/ax_boost_base.m4:
Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
Copyright (c) 2009 Peter Adolphs
Copying and distribution of this file, with or without modification, are
permitted in any medium without royalty provided the copyright notice
and this notice are preserved. This file is offered as-is, without any
warranty.
* in build/ac-macros/ax_boost_unit_test_framework.m4:
Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
Copying and distribution of this file, with or without modification, are
permitted in any medium without royalty provided the copyright notice
and this notice are preserved. This file is offered as-is, without any
warranty.

View File

@ -56,6 +56,8 @@ SVN_XML_LIBS = @SVN_XML_LIBS@
SVN_ZLIB_LIBS = @SVN_ZLIB_LIBS@
SVN_LZ4_LIBS = @SVN_LZ4_LIBS@
SVN_UTF8PROC_LIBS = @SVN_UTF8PROC_LIBS@
SVN_MACOS_PLIST_LIBS = @SVN_MACOS_PLIST_LIBS@
SVN_MACOS_KEYCHAIN_LIBS = @SVN_MACOS_KEYCHAIN_LIBS@
LIBS = @LIBS@
@ -78,6 +80,9 @@ datadir = @datadir@
datarootdir = @datarootdir@
localedir = @localedir@
# where to install SVN++
svnxx_libdir = @libdir@
# where to install libsvn_swig_*
swig_py_libdir = @libdir@
swig_pl_libdir = @libdir@
@ -139,16 +144,17 @@ APACHE_INCLUDES = @APACHE_INCLUDES@
APACHE_LIBEXECDIR = $(DESTDIR)@APACHE_LIBEXECDIR@
APACHE_LDFLAGS = @APACHE_LDFLAGS@
SVN_USE_GOOGLEMOCK = @SVN_USE_GOOGLEMOCK@
GOOGLEMOCK_INCLUDES = -I@GOOGLEMOCK_SRCDIR@/googlemock/include -I@GOOGLEMOCK_SRCDIR@/googletest/include
GOOGLEMOCK_LIB_INCLUDES = -I@GOOGLEMOCK_SRCDIR@/googlemock -I@GOOGLEMOCK_SRCDIR@/googletest $(GOOGLEMOCK_INCLUDES)
BOOST_TEST_CPPFLAGS = @BOOST_CPPFLAGS@ -DBOOST_TEST_DYN_LINK -DBOOST_TEST_NO_MAIN
BOOST_TEST_LDFLAGS = @BOOST_LDFLAGS@ @BOOST_UNIT_TEST_FRAMEWORK_LIB@
SWIG = @SWIG@
SWIG_PY_INCLUDES = @SWIG_PY_INCLUDES@ -I$(SWIG_SRC_DIR)/python/libsvn_swig_py
SWIG_PY_INCLUDES = @SWIG_PY_INCLUDES@ @SVN_PY3C_INCLUDES@ -I$(SWIG_SRC_DIR)/python/libsvn_swig_py
SWIG_PY_COMPILE = @SWIG_PY_COMPILE@
SWIG_PY_LINK = @SWIG_PY_LINK@
SWIG_PY_LIBS = @SWIG_PY_LIBS@
SWIG_PY_ERRMSG = @SWIG_PY_ERRMSG@
SWIG_PL_INCLUDES = @SWIG_PL_INCLUDES@
SWIG_PL_ERRMSG = @SWIG_PL_ERRMSG@
SWIG_RB_INCLUDES = @SWIG_RB_INCLUDES@ -I$(SWIG_SRC_DIR)/ruby/libsvn_swig_ruby
SWIG_RB_COMPILE = @SWIG_RB_COMPILE@
SWIG_RB_LINK = @SWIG_RB_LINK@
@ -157,6 +163,7 @@ SWIG_RB_SITE_LIB_DIR = @SWIG_RB_SITE_LIB_DIR@
SWIG_RB_SITE_ARCH_DIR = @SWIG_RB_SITE_ARCH_DIR@
SWIG_RB_TEST_VERBOSE = @SWIG_RB_TEST_VERBOSE@
SWIG_RB_RI_DATADIR = $(DESTDIR)$(datadir)/ri/$(RUBY_MAJOR).$(RUBY_MINOR)/site
SWIG_RB_ERRMSG = @SWIG_RB_ERRMSG@
CTYPESGEN = @CTYPESGEN@
CTYPES_PYTHON_SRC_DIR = $(abs_srcdir)/subversion/bindings/ctypes-python
@ -164,7 +171,9 @@ CTYPES_PYTHON_SRC_DIR = $(abs_srcdir)/subversion/bindings/ctypes-python
JAVAHL_JAR=subversion/bindings/javahl/svn-javahl.jar
JAVAHL_INCLUDES= @JNI_INCLUDES@ -I$(abs_builddir)/subversion/bindings/javahl/include
CXXHL_INCLUDES = -I$(abs_srcdir)/subversion/bindings/cxxhl/include
SVN_BUILD_SVNXX = @SVN_BUILD_SVNXX@
SVN_BUILD_SVNXX_TESTS = @SVN_BUILD_SVNXX_TESTS@
SVNXX_INCLUDES = -I$(abs_srcdir)/subversion/bindings/cxx/include
SVN_APR_CONFIG = @SVN_APR_CONFIG@
SVN_APR_INCLUDES = @SVN_APR_INCLUDES@
@ -194,6 +203,7 @@ SWIG_FEATURES = @SWIG_FEATURES@
SWIG_PY_FEATURES = @SWIG_PY_FEATURES@
SWIG_PL_FEATURES = @SWIG_PL_FEATURES@
SWIG_RB_FEATURES = @SWIG_RB_FEATURES@
SWIG_PY_OPTS = @SWIG_PY_OPTS@
COMPILE = $(CC) $(CMODEFLAGS) $(CPPFLAGS) $(CMAINTAINERFLAGS) $(CFLAGS) $(INCLUDES)
COMPILE_NOWARN = $(CC) $(CMODEFLAGS) $(CPPFLAGS) $(CNOWARNFLAGS) $(CFLAGS) $(INCLUDES)
@ -218,7 +228,6 @@ COMPILE_SWIG_RB = $(LIBTOOL) $(LTFLAGS) --mode=compile $(SWIG_RB_COMPILE) $(CPPF
# special compilation for files destined for javahl (i.e. C++)
COMPILE_JAVAHL_CXX = $(LIBTOOL) $(LTCXXFLAGS) --mode=compile $(COMPILE_CXX) $(LT_CFLAGS) $(JAVAHL_INCLUDES) -o $@ -c
COMPILE_JAVAHL_JAVAC = $(JAVAC) $(JAVAC_FLAGS)
COMPILE_JAVAHL_JAVAH = $(JAVAH)
COMPILE_JAVAHL_COMPAT_JAVAC = $(JAVAC) $(JAVAC_COMPAT_FLAGS)
# On Mac OS X, export an env variable so that the tests can run without
@ -259,15 +268,15 @@ TEST_SHLIB_VAR_SWIG_RB=\
export @SVN_APR_SHLIB_PATH_VAR@; \
fi;
# special compilation for files destined for cxxhl
COMPILE_CXXHL_CXX = $(LT_COMPILE_CXX) $(CXXHL_INCLUDES) -o $@ -c
COMPILE_GOOGLEMOCK_CXX = $(LT_COMPILE_CXX_NOWARN) $(GOOGLEMOCK_LIB_INCLUDES) -o $@ -c
COMPILE_CXXHL_GOOGLEMOCK_CXX = $(LT_COMPILE_CXX) $(CXXHL_INCLUDES) $(GOOGLEMOCK_INCLUDES) -o $@ -c
# special compilation for files destined for SVN++
COMPILE_SVNXX = $(LT_COMPILE_CXX) $(SVNXX_INCLUDES) -o $@ -c
COMPILE_SVNXX_TEST = $(LT_COMPILE_CXX) $(SVNXX_INCLUDES) $(BOOST_TEST_CPPFLAGS) -o $@ -c
LINK = $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LT_LDFLAGS) $(CFLAGS) $(LDFLAGS) -rpath $(libdir)
LINK_LIB = $(LINK) $(LT_SO_VERSION)
LINK_CXX = $(LIBTOOL) $(LTCXXFLAGS) --mode=link $(CXX) $(LT_LDFLAGS) $(CXXFLAGS) $(LDFLAGS) -rpath $(libdir)
LINK_CXX_LIB = $(LINK_CXX) $(LT_SO_VERSION)
LINK_SVNXX_TEST = $(LINK_CXX) $(BOOST_TEST_LDFLAGS)
# special link rule for mod_dav_svn
LINK_APACHE_MOD = $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LT_LDFLAGS) $(CFLAGS) $(LDFLAGS) -rpath $(APACHE_LIBEXECDIR) -avoid-version -module $(APACHE_LDFLAGS) -shared
@ -321,6 +330,8 @@ INSTALL_DATA = $(INSTALL) -m 644
INSTALL_LOCALE = $(INSTALL_DATA)
INSTALL_APACHE_MODS = @INSTALL_APACHE_MODS@
INSTALL_SVNXX_LIB = $(INSTALL_LIB)
### this isn't correct yet
INSTALL_SWIG_PY = $(INSTALL_LIB)
INSTALL_SWIG_PY_LIB = $(INSTALL_LIB)
@ -393,7 +404,6 @@ JAVAC = @JAVAC@
JAVADOC = @JAVADOC@
JAVAC_FLAGS = @JAVAC_FLAGS@
JAVAC_COMPAT_FLAGS = @JAVAC_COMPAT_FLAGS@
JAVAH = @JAVAH@
JAR = @JAR@
JAVA_CLASSPATH=$(abs_srcdir)/subversion/bindings/javahl/src:@JAVA_CLASSPATH@
@ -494,8 +504,8 @@ revision-install:
install-static: @INSTALL_STATIC_RULES@
# JavaHL target aliases
javahl: mkdir-init javahl-java javahl-javah javahl-callback-javah javahl-remote-javah javahl-types-javah javahl-util-javah javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
install-javahl: javahl install-javahl-java install-javahl-javah install-javahl-lib
javahl: mkdir-init javahl-java javahl-callback-java javahl-remote-java javahl-types-java javahl-util-java javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
install-javahl: javahl install-javahl-java install-javahl-lib
javahl-compat: javahl-compat-java @JAVAHL_COMPAT_TESTS_TARGET@
clean-javahl:
@ -526,6 +536,9 @@ check-javahl: check-apache-javahl
check-all-javahl: check-apache-javahl check-tigris-javahl check-deprecated-authn-javahl
check-svnxx: svnxx-tests
$(abs_builddir)/$(svnxx_tests_PATH)/svnxx-tests$(EXEEXT)
# "make check CLEANUP=true" will clean up directories for successful tests.
# "make check TESTS=subversion/tests/cmdline/basic_tests.py"
# will perform only basic tests (likewise for other tests).
@ -601,6 +614,9 @@ check: bin @TRANSFORM_LIBTOOL_SCRIPTS@ $(TEST_DEPS) @BDB_TEST_DEPS@
if test "$(FSFS_DIR_DELTIFICATION)" != ""; then \
flags="--fsfs-dir-deltification $(FSFS_DIR_DELTIFICATION) $$flags";\
fi; \
if test "$(ALLOW_REMOTE_HTTP_CONNECTION)" != ""; then \
flags="--allow-remote-http-connection $$flags"; \
fi; \
if test "$(SVN_BIN_DIR)" != ""; then \
flags="--bin $(SVN_BIN_DIR) $$flags"; \
fi; \
@ -674,7 +690,7 @@ gcov-reset:
gcov-clean:
rm -f gcov-lcov.dat gcov-lcov.log gcov-genhtml.log
rm -rf gcov-report
find . -name "*.gcda" -o -name "*.gcno" -exec rm -f -- {} \;
find . \( -name "*.gcda" -o -name "*.gcno" \) -exec rm -f -- {} \;
check-clean: gcov-clean
if [ -d subversion/tests/cmdline/svn-test-work ]; then \
@ -694,7 +710,8 @@ check-clean: gcov-clean
subversion/tests/libsvn_diff/T1 \
subversion/tests/libsvn_diff/T2 \
subversion/tests/libsvn_diff/T3 \
subversion/tests/svnserveautocheck.pid \
subversion/tests/cmdline/httpd-* \
subversion/tests/cmdline/svnserve-* \
tests.log fails.log
mkdir-init:
@ -895,6 +912,7 @@ EXTRACLEAN_SWIG_PL=rm -f $(SWIG_PL_SRC_DIR)/native/svn_*.c \
# Makefile does not exist, DO NOT try to make it. But, if it doesn't exist,
# then the directory is probably clean anyway.
clean-swig-pl:
rm -f .swig_pl_checked
if test -z "$(RELEASE_MODE)"; then \
$(EXTRACLEAN_SWIG_PL); \
fi
@ -917,6 +935,7 @@ copy-swig-py: autogen-swig-py $(SWIG_PY_DIR)/libsvn
@for f in $(SWIG_PY_SRC_DIR)/*.py $(SWIG_PY_DIR)/*.py; do \
! [ -f "$$f" ] || cp -pf $$f $(SWIG_PY_DIR)/libsvn; \
done
@cd $(SWIG_PY_DIR)/libsvn;ln -sf ../.libs/*.so .
@touch $(SWIG_PY_DIR)/libsvn/__init__.py
swig-py: autogen-swig-py copy-swig-py
@ -926,9 +945,10 @@ check-swig-py: swig-py
cd $(SWIG_PY_DIR); \
$(PYTHON) $(SWIG_PY_SRC_DIR)/tests/run_all.py
EXTRACLEAN_SWIG_PY=rm -rf $(SWIG_PY_SRC_DIR)/svn_*.c $(SWIG_PY_SRC_DIR)/core.c \
$(SWIG_PY_SRC_DIR)/[a-z]*.py
EXTRACLEAN_SWIG_PY=rm -rf $(SWIG_PY_DIR)/svn_*.c $(SWIG_PY_DIR)/core.c \
$(SWIG_PY_DIR)/[a-z]*.py
clean-swig-py:
rm -f .swig_py_checked
rm -rf $(SWIG_PY_DIR)/libsvn
if test -z "$(RELEASE_MODE)"; then \
$(EXTRACLEAN_SWIG_PY); \
@ -961,6 +981,7 @@ check-swig-rb: swig-rb svnserve
EXTRACLEAN_SWIG_RB=rm -f $(SWIG_RB_SRC_DIR)/svn_*.c $(SWIG_RB_SRC_DIR)/core.c
clean-swig-rb:
rm -f .swig_rb_checked
rm -rf $(SWIG_RB_DIR)/test/repos $(SWIG_RB_DIR)/test/wc
if test -z "$(RELEASE_MODE)"; then \
$(EXTRACLEAN_SWIG_RB); \

View File

@ -1,5 +1,5 @@
Apache Subversion
Copyright 2018 The Apache Software Foundation
Copyright 2020 The Apache Software Foundation
This product includes software developed by many people, and distributed
under Contributor License Agreements to The Apache Software Foundation
@ -29,3 +29,6 @@ license, see LICENSE.
This product includes code derived from the software developed by Yann Collet
under a BSD 2-Clause license, see LICENSE.
This product includes code derived from the software developed by Thomas
Porschberg and Peter Adolphs under a permissive license, see LICENSE.

View File

@ -35,6 +35,8 @@ sinclude(build/ac-macros/apache.m4)
sinclude(build/ac-macros/apr.m4)
sinclude(build/ac-macros/aprutil.m4)
sinclude(build/ac-macros/apr_memcache.m4)
sinclude(build/ac-macros/ax_boost_base.m4)
sinclude(build/ac-macros/ax_boost_unit_test_framework.m4)
sinclude(build/ac-macros/berkeley-db.m4)
sinclude(build/ac-macros/compiler.m4)
sinclude(build/ac-macros/ctypesgen.m4)
@ -42,6 +44,7 @@ sinclude(build/ac-macros/java.m4)
sinclude(build/ac-macros/sasl.m4)
sinclude(build/ac-macros/serf.m4)
sinclude(build/ac-macros/sqlite.m4)
sinclude(build/ac-macros/py3c.m4)
sinclude(build/ac-macros/swig.m4)
sinclude(build/ac-macros/zlib.m4)
sinclude(build/ac-macros/lz4.m4)

View File

@ -176,7 +176,7 @@ if test -n "$RELEASE_MODE"; then
"$PYTHON" ./gen-make.py build.conf || gen_failed=1
# Build the SWIG-related files
make -f autogen-standalone.mk autogen-swig
make -f autogen-standalone.mk autogen-swig || gen_failed=1
# Remove the .swig_checked file
rm -f .swig_checked

File diff suppressed because one or more lines are too long

View File

@ -38,11 +38,14 @@ private-includes =
subversion/include/private/*.h
subversion/bindings/swig/include/*.swg
subversion/libsvn_delta/compose_delta.c
subversion/bindings/cxxhl/include/*.hpp
subversion/bindings/cxxhl/include/svncxxhl/*.hpp
subversion/bindings/cxxhl/src/*.hpp
subversion/bindings/cxxhl/src/aprwrap/*.hpp
subversion/bindings/cxxhl/src/private/*.hpp
subversion/bindings/cxx/include/*.hpp
subversion/bindings/cxx/include/svnxx/*.hpp
subversion/bindings/cxx/include/svnxx/client/*.hpp
subversion/bindings/cxx/include/svnxx/detail/*.hpp
subversion/bindings/cxx/src/*.hpp
subversion/bindings/cxx/src/aprwrap/*.hpp
subversion/bindings/cxx/src/private/*.hpp
subversion/bindings/cxx/tests/*.hpp
subversion/bindings/javahl/native/*.hpp
subversion/bindings/javahl/native/jniwrapper/jni_*.hpp
tools/dev/svnmover/linenoise/linenoise.h
@ -98,7 +101,7 @@ test-scripts =
bdb-test-scripts =
swig-python-opts = $(SWIG_FEATURES) -python $(SWIG_PY_FEATURES) -classic
swig-python-opts = $(SWIG_FEATURES) $(SWIG_PY_OPTS) $(SWIG_PY_FEATURES)
swig-perl-opts = $(SWIG_FEATURES) -perl $(SWIG_PL_FEATURES) -nopm -noproxy
swig-ruby-opts = $(SWIG_FEATURES) -ruby $(SWIG_RB_FEATURES)
swig-languages = python perl ruby
@ -245,7 +248,7 @@ type = lib
path = subversion/libsvn_client
libs = libsvn_wc libsvn_ra libsvn_delta libsvn_diff libsvn_subr apriconv apr
install = lib
msvc-export = svn_client.h private/svn_client_mtcc.h private/svn_client_private.h
msvc-export = svn_client.h private/svn_client_mtcc.h private/svn_client_private.h private/svn_client_shelf.h private/svn_client_shelf2.h
# Routines for binary diffing and tree-deltas
[libsvn_delta]
@ -371,7 +374,8 @@ type = lib
install = fsmod-lib
path = subversion/libsvn_subr
sources = *.c lz4/*.c
libs = aprutil apriconv apr xml zlib apr_memcache sqlite magic intl lz4 utf8proc
libs = aprutil apriconv apr xml zlib apr_memcache
sqlite magic intl lz4 utf8proc macos-plist macos-keychain
msvc-libs = kernel32.lib advapi32.lib shfolder.lib ole32.lib
crypt32.lib version.lib
msvc-export =
@ -392,7 +396,7 @@ msvc-export =
private\svn_string_private.h private\svn_magic.h
private\svn_subr_private.h private\svn_mutex.h
private\svn_packed_data.h private\svn_object_pool.h private\svn_cert.h
private\svn_config_private.h
private\svn_config_private.h private\svn_dirent_uri_private.h
# Working copy management lib
[libsvn_wc]
@ -438,7 +442,7 @@ description = Subversion FSFS Repository Manipulation Tool
type = exe
path = subversion/svnfsfs
install = bin
libs = libsvn_repos libsvn_fs libsvn_fs_fs libsvn_delta libsvn_subr apriconv apr
libs = libsvn_repos libsvn_fs libsvn_delta libsvn_subr apriconv apr
# ----------------------------------------------------------------------------
#
@ -608,16 +612,14 @@ msvc-export = ../bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h
[javahl-java]
type = java
path = subversion/bindings/javahl/src/org/apache/subversion/javahl
subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
subversion/bindings/javahl/src/org/apache/subversion/javahl/types
subversion/bindings/javahl/src/org/apache/subversion/javahl/util
src-root = subversion/bindings/javahl/src
sources = *.java
native = CommitItemStateFlags.java NativeResources.java SVNClient.java
SVNRepos.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
classes = subversion/bindings/javahl/classes
package-roots = org
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl
[javahl-compat-java]
type = java
@ -626,10 +628,12 @@ sources = *.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_COMPAT_JAVAC)
classes = subversion/bindings/javahl/classes
add-deps = $(javahl_java_DEPS)
add-deps = $(javahl_callback_java_DEPS) $(javahl_remote_java_DEPS)
$(javahl_types_java_DEPS) $(javahl_util_java_DEPS)
$(javahl_java_DEPS)
### Replace JAR call in INSTALL_EXTRA_JAVAHL_JAVA macro Makefile.in.
#jar = svn-javahl.jar
package-roots = org
package = org.tigris.subversion.javahl
[javahl-tests]
type = java
@ -638,10 +642,12 @@ sources = *.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
classes = subversion/bindings/javahl/classes
package-roots = org
package = org.apache.subversion.javahl
### Java targets don't do up-to-date checks yet.
#add-deps = javahl-java
add-deps = $(javahl_java_DEPS)
add-deps = $(javahl_callback_java_DEPS) $(javahl_remote_java_DEPS)
$(javahl_types_java_DEPS) $(javahl_util_java_DEPS)
$(javahl_java_DEPS)
[javahl-compat-tests]
type = java
@ -650,65 +656,59 @@ sources = *.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_COMPAT_JAVAC)
classes = subversion/bindings/javahl/classes
package-roots = org
package = org.tigris.subversion.javahl
### Java targets don't do up-to-date checks yet.
#add-deps = javahl-compat-java
add-deps = $(javahl_compat_java_DEPS)
[javahl-callback-javah]
type = javah
[javahl-callback-java]
type = java
path = subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
classes = subversion/bindings/javahl/classes
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl.callback
sources = *.java
add-deps = $(javahl_java_DEPS)
install = javahl-javah
link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
native = UserPasswordCallback.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
[javahl-remote-javah]
type = javah
[javahl-remote-java]
type = java
path = subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
classes = subversion/bindings/javahl/classes
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl.remote
sources = *.java
add-deps = $(javahl_java_DEPS)
install = javahl-javah
link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
native = CommitEditor.java RemoteFactory.java RemoteSession.java
StateReporter.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
[javahl-types-javah]
type = javah
[javahl-types-java]
type = java
path = subversion/bindings/javahl/src/org/apache/subversion/javahl/types
classes = subversion/bindings/javahl/classes
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl.types
sources = *.java
add-deps = $(javahl_java_DEPS)
install = javahl-javah
link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
native = NativeInputStream.java NativeOutputStream.java Revision.java
RevisionRangeList.java RuntimeVersion.java VersionExtended.java
Version.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
[javahl-util-javah]
type = javah
[javahl-util-java]
type = java
path = subversion/bindings/javahl/src/org/apache/subversion/javahl/util
classes = subversion/bindings/javahl/classes
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl.util
sources = *.java
add-deps = $(javahl_java_DEPS)
install = javahl-javah
link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
[javahl-javah]
type = javah
path = subversion/bindings/javahl/src/org/apache/subversion/javahl
classes = subversion/bindings/javahl/classes
headers = subversion/bindings/javahl/include
package = org.apache.subversion.javahl
sources = *.java
add-deps = $(javahl_java_DEPS)
install = javahl-javah
link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
native = ConfigImpl.java ConfigLib.java DiffLib.java PropLib.java
RequestChannel.java ResponseChannel.java SubstLib.java
TunnelChannel.java
install = javahl-java
link-cmd = $(COMPILE_JAVAHL_JAVAC)
[libsvnjavahl]
description = Subversion Java HighLevel binding
@ -717,9 +717,9 @@ path = subversion/bindings/javahl/native
libs = libsvn_repos libsvn_client libsvn_wc libsvn_ra libsvn_delta libsvn_diff
libsvn_subr libsvn_fs aprutil apriconv apr java-sdk
sources = *.cpp jniwrapper/*.cpp
add-deps = $(javahl_java_DEPS) $(javahl_callback_javah_DEPS)
$(javahl_remote_javah_DEPS) $(javahl_types_javah_DEPS)
$(javahl_util_javah_DEPS) $(javahl_javah_DEPS)
add-deps = $(javahl_java_DEPS) $(javahl_callback_java_DEPS)
$(javahl_remote_java_DEPS) $(javahl_types_java_DEPS)
$(javahl_util_java_DEPS) $(javahl_java_DEPS)
install = javahl-lib
# need special build rule to include -I$(JDK)/include/jni.h
compile-cmd = $(COMPILE_JAVAHL_CXX)
@ -727,48 +727,34 @@ link-cmd = $(LINK_JAVAHL_CXX)
# ----------------------------------------------------------------------------
#
# C++HL targets
# SVN++ targets
#
[libsvncxxhl]
description = Subversion C++ HighLevel bindings
[libsvnxx]
description = Subversion C++ bindings
when = SVN_BUILD_SVNXX
type = lib
path = subversion/bindings/cxxhl
path = subversion/bindings/cxx
libs = libsvn_repos libsvn_client libsvn_wc libsvn_ra libsvn_delta libsvn_diff
libsvn_subr libsvn_fs aprutil apriconv apr
sources = src/*.cpp src/aprwrap/*.cpp
install = cxxhl-lib
install = svnxx-lib
msvc-static = yes
compile-cmd = $(COMPILE_CXXHL_CXX)
compile-cmd = $(COMPILE_SVNXX)
link-cmd = $(LINK_CXX_LIB)
[cxxhl-tests]
description = Unit tests for Subversion C++ HighLevel bindings
when = SVN_USE_GOOGLEMOCK
[svnxx-tests]
description = Unit tests for Subversion C++ bindings
when = SVN_BUILD_SVNXX_TESTS
type = exe
path = subversion/bindings/cxxhl
libs = libsvncxxhl libgooglemock libsvn_subr apr
path = subversion/bindings/cxx
libs = libsvnxx
libsvn_repos libsvn_client libsvn_wc libsvn_ra libsvn_delta libsvn_diff
libsvn_subr libsvn_fs aprutil apriconv apr
sources = tests/*.cpp
install = cxxhl-tests
compile-cmd = $(COMPILE_CXXHL_GOOGLEMOCK_CXX)
link-cmd = $(LINK_CXX)
# ----------------------------------------------------------------------------
#
# Googlemock targets
#
[libgooglemock]
description = Googlemock Library
when = SVN_USE_GOOGLEMOCK
type = lib
path = googlemock
sources = googletest/src/gtest-all.cc googlemock/src/gmock-all.cc
install = cxxhl-tests
msvc-static = yes
compile-cmd = $(COMPILE_GOOGLEMOCK_CXX)
link-cmd = $(LINK_CXX_LIB)
install = svnxx-tests
compile-cmd = $(COMPILE_SVNXX_TEST)
link-cmd = $(LINK_SVNXX_TEST)
# ----------------------------------------------------------------------------
#
@ -1463,7 +1449,8 @@ external-lib = $(SVN_DB_LIBS)
[gnome-keyring]
type = lib
external-lib = $(SVN_GNOME_KEYRING_LIBS)
pkg-config = gnome-keyring-1
pkg-config = @SVN_GNOME_KEYRING_PCLIBS@
pkg-config-private = yes
[kwallet]
type = lib
@ -1473,6 +1460,14 @@ external-lib = $(SVN_KWALLET_LIBS)
type = lib
external-lib = $(SVN_MAGIC_LIBS)
[macos-plist]
type = lib
external-lib = $(SVN_MACOS_PLIST_LIBS)
[macos-keychain]
type = lib
external-lib = $(SVN_MACOS_KEYCHAIN_LIBS)
[sasl]
type = lib
external-lib = $(SVN_SASL_LIBS)
@ -1587,7 +1582,7 @@ libs = __ALL__
conflict-data-test db-test pristine-store-test entries-compat-test
op-depth-test dirent_uri-test wc-queries-test wc-test
auth-test
parse-diff-test x509-test xml-test afl-x509 compress-test
parse-diff-test x509-test xml-test afl-x509 afl-svndiff compress-test
svndiff-stream-test
[__MORE__]
@ -1629,7 +1624,7 @@ lang = ruby
[__JAVAHL__]
type = project
path = build/win32
libs = javahl-java javahl-javah libsvnjavahl
libs = javahl-java libsvnjavahl
[__JAVAHL_TESTS__]
type = project
@ -1748,3 +1743,12 @@ sources = afl-x509.c
install = test
libs = libsvn_subr apr
testing = skip
[afl-svndiff]
description = AFL fuzzer for svndiff to txdelta parser
type = exe
path = subversion/tests/afl
sources = afl-svndiff.c
install = test
libs = libsvn_delta libsvn_subr apr
testing = skip

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ AC_PREREQ(2.59)
dnl Get the version of Subversion, using m4's esyscmd() command to do this
dnl at m4-time, since AC_INIT() requires it then.
AC_INIT([subversion],
[esyscmd(python build/getversion.py SVN subversion/include/svn_version.h)],
[esyscmd($PYTHON build/getversion.py SVN subversion/include/svn_version.h)],
[http://subversion.apache.org/])
AC_CONFIG_SRCDIR(subversion/include/svn_types.h)
@ -91,7 +91,7 @@ AC_SUBST([MKDIR])
dnl verify apr version and set apr flags
dnl These regular expressions should not contain "\(" and "\)".
APR_VER_REGEXES=["1\.[3-9]\. 2\."]
APR_VER_REGEXES=["1\.[5-9]\. 2\."]
SVN_LIB_APR($APR_VER_REGEXES)
@ -593,6 +593,7 @@ if test "$with_old_gnome_keyring" != "no"; then
[Is GNOME Keyring support enabled?])
CPPFLAGS="$old_CPPFLAGS"
SVN_GNOME_KEYRING_LIBS="`$PKG_CONFIG --libs glib-2.0 gnome-keyring-1`"
SVN_GNOME_KEYRING_PCLIBS="glib-2.0, gnome-keyring-1"
else
AC_MSG_RESULT([no])
if test "$with_old_gnome_keyring" = "yes"; then
@ -639,29 +640,6 @@ AC_SUBST(SVN_GNOME_KEYRING_LIBS)
dnl LibSecret -------------------
SVN_LIB_SECRET
dnl Googlemock -----------------
AC_ARG_ENABLE([googlemock],
AS_HELP_STRING([--disable-googlemock],
[Do not use the Googlemock testing framework]),
[],
[enable_googlemock=yes])
AC_SUBST([GOOGLEMOCK_SRCDIR], [$abs_srcdir/googlemock])
AC_MSG_CHECKING([whether use Googlemock])
if test "$enable_googlemock" != "no"; then
if test -d "$GOOGLEMOCK_SRCDIR"; then
AC_MSG_RESULT([yes])
SVN_USE_GOOGLEMOCK=true
else
AC_MSG_RESULT([no])
SVN_USE_GOOGLEMOCK=false
fi
else
AC_MSG_RESULT([no])
SVN_USE_GOOGLEMOCK=false
fi
AC_SUBST([SVN_USE_GOOGLEMOCK])
dnl Ev2 experimental features ----------------------
dnl Note: The Ev2 implementations will be built unconditionally, but by
dnl providing this flag, users can choose to use the currently-shimmed Ev2
@ -866,18 +844,21 @@ fi
dnl plaintext passwords -------------------
AC_ARG_ENABLE(plaintext-password-storage,
AS_HELP_STRING([--disable-plaintext-password-storage],
[Disable on-disk caching of plaintext passwords and passphrases.
(Leaving this functionality enabled will not force Subversion
AS_HELP_STRING([--enable-plaintext-password-storage],
[Enable on-disk caching of plaintext passwords and passphrases.
(Enabling this functionality will not force Subversion
to store passwords in plaintext, but does permit users to
explicitly allow that behavior via runtime configuration.)]),
[
if test "$enableval" = "no"; then
AC_MSG_NOTICE([Disabling plaintext password/passphrase storage])
AC_DEFINE(SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE, 1,
[Defined if plaintext password/passphrase storage is disabled])
fi
])
[plaintext_passwordd_storage="$enableval"],
[plaintext_passwordd_storage="no"])
if test "$plaintext_passwordd_storage" = "yes"; then
AC_MSG_WARN([Enabling plaintext password/passphrase storage])
else
AC_MSG_NOTICE([Disabling plaintext password/passphrase storage])
AC_DEFINE(SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE, 1,
[Defined if plaintext password/passphrase storage is disabled])
fi
dnl Build and install rules -------------------
@ -947,8 +928,9 @@ AC_FUNC_VPRINTF
dnl check for functions needed in special file handling
AC_CHECK_FUNCS(symlink readlink)
dnl check for uname
dnl check for uname and ELF headers
AC_CHECK_HEADERS(sys/utsname.h, [AC_CHECK_FUNCS(uname)], [])
AC_CHECK_HEADERS(elf.h)
dnl check for termios
AC_CHECK_HEADER(termios.h,[
@ -1152,7 +1134,6 @@ if test "$enable_optimization" = "yes"; then
SVN_CFLAGS_ADD_IFELSE([-O1],[],[
SVN_CFLAGS_ADD_IFELSE([-O])])])])
SVN_CFLAGS_ADD_IFELSE([-Wno-clobbered])
SVN_CFLAGS_ADD_IFELSE([-flto])
fi
fi
if test -z ["`echo $CXXUSERFLAGS' ' | $EGREP -- '-O[^ ]* '`"]; then
@ -1168,7 +1149,6 @@ if test "$enable_optimization" = "yes"; then
SVN_CXXFLAGS_ADD_IFELSE([-O1],[],[
SVN_CXXFLAGS_ADD_IFELSE([-O])])])])
SVN_CXXFLAGS_ADD_IFELSE([-Wno-clobbered])
SVN_CXXFLAGS_ADD_IFELSE([-flto])
fi
fi
elif test "$enable_optimization" = "no"; then
@ -1182,9 +1162,11 @@ fi
dnl Dump the current compiler options
AC_MSG_NOTICE([C compiler flags: $CFLAGS])
AC_MSG_NOTICE([ language-level: $CMODEFLAGS])
AC_MSG_NOTICE([ user-defined: $CUSERFLAGS])
AC_MSG_NOTICE([ maintainer-mode: $CMAINTAINERFLAGS])
AC_MSG_NOTICE([C++ compiler flags: $CXXFLAGS])
AC_MSG_NOTICE([ language-level: $CXXMODEFLAGS])
AC_MSG_NOTICE([ user-defined: $CXXUSERFLAGS])
AC_MSG_NOTICE([ maintainer-mode: $CXXMAINTAINERFLAGS])
@ -1291,7 +1273,7 @@ AS_HELP_STRING([--enable-gprof],
# Scripting and Bindings languages
# Python: Used for testsuite, and bindings
AC_ARG_VAR([PYTHON], [Python interpreter command])
PYTHON="`$abs_srcdir/build/find_python.sh`"
if test -z "$PYTHON"; then
@ -1305,7 +1287,7 @@ fi
AC_PATH_PROGS(PYTHON, "$PYTHON", none)
# The minimum version for the JVM runtime for our Java bytecode.
JAVA_OLDEST_WORKING_VER='1.6'
JAVA_OLDEST_WORKING_VER='1.8'
# SVN_CHECK_JDK sets $JAVA_CLASSPATH
SVN_CHECK_JDK($JAVA_OLDEST_WORKING_VER)
@ -1323,7 +1305,7 @@ if test "$RUBY" != "none"; then
if test -n "$RDOC"; then
AC_PATH_PROG(RDOC, "$RDOC", none)
else
AC_PATH_PROGS(RUBY, rdoc rdoc1 rdoc1.8 rdoc18 rdoc1.9 rdoc19 rdoc1.9.3 rdoc193 rdoc2 rdoc2.0 rdoc20 rdoc2.1 rdoc21 rdoc2.2 rdoc22 rdoc2.3 rdoc23 rdoc2.4 rdoc24, none)
AC_PATH_PROGS(RDOC, rdoc rdoc1 rdoc1.8 rdoc18 rdoc1.9 rdoc19 rdoc1.9.3 rdoc193 rdoc2 rdoc2.0 rdoc20 rdoc2.1 rdoc21 rdoc2.2 rdoc22 rdoc2.3 rdoc23 rdoc2.4 rdoc24, none)
fi
AC_CACHE_CHECK([for Ruby major version], [svn_cv_ruby_major],[
svn_cv_ruby_major="`$RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MAJOR))'`"
@ -1453,6 +1435,69 @@ AC_SUBST(SVN_FS_LIB_DEPS)
AC_SUBST(SVN_FS_LIB_INSTALL_DEPS)
AC_SUBST(SVN_FS_LIB_LINK)
# ==== SVN++ =================================================================
dnl Possibly compile SVN++
do_svnxx_build=no
AC_ARG_ENABLE(svnxx,
AS_HELP_STRING([--enable-svnxx],
[Enable compilation of the C++ bindings (requires C++)]),
[ if test "$enableval" = "yes" ; then
AC_MSG_NOTICE([Enabling the C++ bindings])
do_svnxx_build=yes
fi
])
dnl Possibly compile SVN++ tests
do_svnxx_test_build=no
AC_ARG_ENABLE(svnxx-tests,
AS_HELP_STRING([--enable-svnxx-tests],
[Enable compilation of tests for the C++ bindings
(implies --enable-svnxx, requires Boost and Boost.Test)]),
[ if test "$enableval" = "yes" ; then
AC_MSG_NOTICE([Enabling tests for the C++ bindings])
do_svnxx_test_build=yes
fi
])
AX_BOOST_BASE([1.58],
[
if test "$do_svnxx_test_build" = "yes"; then
AX_BOOST_UNIT_TEST_FRAMEWORK
fi
],
[
if test "$do_svnxx_test_build" = "yes"; then
AC_MSG_WARN([Tests for the C++ bindings require Boost and Boost.Test])
do_svnxx_test_build=no
fi
])
if test "$do_svnxx_test_build" = "yes"; then
if test "$want_boost" != "yes"; then
AC_MSG_WARN([Tests for the C++ bindings require Boost and Boost.Test])
do_svnxx_test_build=no
SVN_BUILD_SVNXX_TESTS=false
else
if test "$do_svnxx_build" != "yes"; then
AC_MSG_WARN([Enabling the C++ bindings because their tests are enabled])
do_svnxx_build=yes
fi
SVN_BUILD_SVNXX_TESTS=true
fi
else
SVN_BUILD_SVNXX_TESTS=false
fi
if test "$do_svnxx_build" = "yes"; then
SVN_BUILD_SVNXX=true
else
SVN_BUILD_SVNXX=false
fi
AC_SUBST(SVN_BUILD_SVNXX)
AC_SUBST(SVN_BUILD_SVNXX_TESTS)
# ==== JavaHL ================================================================
dnl Possibly compile JavaHL
@ -1596,7 +1641,7 @@ fi
AC_SUBST(SVN_CONFIG_SCRIPT_FILES)
# Ensure that SWIG is checked after reconfiguration.
rm -f .swig_checked
rm -f .swig_checked .swig_pl_checked .swig_py_checked .swig_rb_checked
dnl Provide ${host} for use in compiled code (for svn --version)
AC_DEFINE_UNQUOTED([SVN_BUILD_HOST], "${host}",

View File

@ -112,7 +112,7 @@ INLINE_INHERITED_MEMB = NO
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
FULL_PATH_NAMES = YES
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
@ -121,7 +121,7 @@ FULL_PATH_NAMES = NO
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
STRIP_FROM_PATH = subversion/include subversion/bindings/cxx/include
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@ -130,7 +130,7 @@ STRIP_FROM_PATH =
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH =
STRIP_FROM_INC_PATH = subversion/include subversion/bindings/cxx/include
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems
@ -280,22 +280,6 @@ SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
# determine which symbols to keep in memory and which to flush to disk.
# When the cache is full, less often used symbols will be written to disk.
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penality.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will rougly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
SYMBOL_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -478,12 +462,6 @@ MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
@ -577,6 +555,10 @@ WARN_LOGFILE =
# with spaces.
INPUT = subversion/include \
subversion/bindings/cxx/include \
subversion/bindings/cxx/include/svnxx \
subversion/bindings/cxx/include/svnxx/client \
subversion/bindings/cxx/include/svnxx/detail \
subversion/include/private/svn_doxygen.h
# This tag can be used to specify the character encoding of the source files
@ -594,7 +576,7 @@ INPUT_ENCODING = UTF-8
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
FILE_PATTERNS = *.h
FILE_PATTERNS = *.h *.hpp
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@ -805,12 +787,6 @@ HTML_FOOTER =
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded. For this to work a browser that supports
@ -959,11 +935,6 @@ ENUM_VALUES_PER_LINE = 1
GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
USE_INLINE_TREES = NO
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
@ -1151,18 +1122,6 @@ GENERATE_XML = NO
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_SCHEMA =
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
@ -1378,7 +1337,7 @@ HAVE_DOT = NO
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
# containing the font.
DOT_FONTNAME = FreeSans
DOT_FONTNAME =
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.

View File

@ -1,30 +0,0 @@
Googlemock and Googletest Suite for Subversion
---------------------------------------------
Googlemock and Googletest are external packages that are downloaded
and compiled on request, as part of regular compilations.
Googlemock is available here:
https://code.google.com/p/googlemock/
The source packages already include Googletest, which is available
here:
https://code.google.com/p/googletest/
Subversion uses Googlemock and Googletest for the C++HL test suite.
To configure Subversion to use Googlemock, type
./get-dep.sh gmock
This will download Googlemock and put the fused source into the
'gmock-fused' directory. Once it's there, configure will pick it up
automatically (but you do have to re-run autogen.sh and configure).
You can disable building Googlemock (and hence the C++HL test suite)
with the --disable-gmock configure option. This will tell configure to
ignore the gmock-fused directory.

View File

@ -240,7 +240,7 @@ while somebody else is in the process of committing.</p>
<li>Users commit their day-to-day work on <tt>/trunk</tt>.</li>
<li>Rule #1: <tt>/trunk</tt> must compile and pass regression tests at
all times. Committers who violate this rule are publically
all times. Committers who violate this rule are publicly
humiliated.</li>
<li>Rule #2: a single commit (changeset) must not be so large

View File

@ -48,7 +48,6 @@
gen_modules = {
'make' : ('gen_make', 'Makefiles for POSIX systems'),
'dsp' : ('gen_msvc_dsp', 'MSVC 6.x project files'),
'vcproj' : ('gen_vcnet_vcproj', 'VC.Net project files'),
}
@ -176,6 +175,8 @@ def _usage_exit(err=None):
print("")
print(" --with-swig=DIR")
print(" look for the swig program in DIR")
print(" --with-py3c=DIR")
print(" look for the py3c library in DIR")
print("")
print(" --with-sqlite=DIR")
print(" look for sqlite in DIR")
@ -215,8 +216,6 @@ def _usage_exit(err=None):
print("")
print(" --with-apr_memcache=DIR")
print(" the apr_memcache sources are in DIR")
print(" --disable-gmock")
print(" do not use Googlemock")
sys.exit(1)
@ -252,6 +251,7 @@ def add(self, opt, val, overwrite=True):
'with-jdk=',
'with-junit=',
'with-swig=',
'with-py3c=',
'with-sqlite=',
'with-sasl=',
'with-apr_memcache=',
@ -264,7 +264,6 @@ def add(self, opt, val, overwrite=True):
'disable-shared',
'installed-libs=',
'vsnet-version=',
'disable-gmock',
])
if len(args) > 1:
_usage_exit("Too many arguments")

View File

@ -31,28 +31,24 @@
# features already used in the file. Reviewing the history of changes
# may be useful as well.
APR_VERSION=${APR_VERSION:-"1.4.6"}
APR_VERSION=${APR_VERSION:-"1.5.0"}
APU_VERSION=${APU_VERSION:-"1.5.1"}
PY3C_VERSION=${PY3C_VERSION:='1.1'}
SERF_VERSION=${SERF_VERSION:-"1.3.8"}
ZLIB_VERSION=${ZLIB_VERSION:-"1.2.8"}
SQLITE_VERSION=${SQLITE_VERSION:-"3.8.11.1"}
# Used to construct the SQLite download URL.
SQLITE_VERSION_REL_YEAR=2015
GTEST_VERSION=${GMOCK_VERSION:-"1.7.0"}
GMOCK_VERSION=${GMOCK_VERSION:-"1.7.0"}
HTTPD_VERSION=${HTTPD_VERSION:-"2.4.10"}
APR_ICONV_VERSION=${APR_ICONV_VERSION:-"1.2.1"}
APR=apr-${APR_VERSION}
APR_UTIL=apr-util-${APU_VERSION}
PY3C=py3c-${PY3C_VERSION}
SERF=serf-${SERF_VERSION}
ZLIB=zlib-${ZLIB_VERSION}
SQLITE_VERSION_LIST=`echo $SQLITE_VERSION | sed -e 's/\./ /g'`
SQLITE=sqlite-amalgamation-`printf %d%02d%02d%02d $SQLITE_VERSION_LIST`
GTEST=release-${GTEST_VERSION}
GTEST_URL=https://github.com/google/googletest/archive
GMOCK=release-${GMOCK_VERSION}
GMOCK_URL=https://github.com/google/googlemock/archive
HTTPD=httpd-${HTTPD_VERSION}
APR_ICONV=apr-iconv-${APR_ICONV_VERSION}
@ -67,12 +63,12 @@ HTTP_FETCH=
# Need this uncommented if any of the specific versions of the ASF tarballs to
# be downloaded are no longer available on the general mirrors.
APACHE_MIRROR=http://archive.apache.org/dist
APACHE_MIRROR=https://archive.apache.org/dist
# helpers
usage() {
echo "Usage: $0"
echo "Usage: $0 [ apr | serf | zlib | sqlite | googlemock ] ..."
echo "Usage: $0 [ apr | py3c | serf | zlib | sqlite ] ..."
exit $1
}
@ -90,6 +86,19 @@ get_apr() {
test -d $BASEDIR/apr-util || mv $APR_UTIL apr-util
}
get_py3c() {
test -d $BASEDIR/py3c && return
py3cdist=v${PY3C_VERSION}.tar.gz
cd $TEMPDIR
$HTTP_FETCH https://github.com/encukou/py3c/archive/${py3cdist}
cd $BASEDIR
gzip -dc $TEMPDIR/${py3cdist} | tar -xf -
mv $PY3C py3c
}
get_serf() {
test -d $BASEDIR/serf && return
@ -106,7 +115,7 @@ get_zlib() {
test -d $BASEDIR/zlib && return
cd $TEMPDIR
$HTTP_FETCH http://sourceforge.net/projects/libpng/files/zlib/$ZLIB_VERSION/$ZLIB.tar.gz
$HTTP_FETCH https://sourceforge.net/projects/libpng/files/zlib/$ZLIB_VERSION/$ZLIB.tar.gz
cd $BASEDIR
gzip -dc $TEMPDIR/$ZLIB.tar.gz | tar -xf -
@ -127,29 +136,11 @@ get_sqlite() {
}
get_googlemock() {
test -d $BASEDIR/googlemock && return
cd $TEMPDIR
$HTTP_FETCH ${GTEST_URL}/${GTEST}.zip
unzip -q ${GTEST}.zip
rm -f ${GTEST}.zip
$HTTP_FETCH ${GMOCK_URL}/${GMOCK}.zip
unzip -q ${GMOCK}.zip
rm -f ${GMOCK}.zip
cd $BASEDIR
mkdir googlemock
mv $TEMPDIR/googletest-release-${GTEST_VERSION} googlemock/googletest
mv $TEMPDIR/googlemock-release-${GMOCK_VERSION} googlemock/googlemock
}
# main()
get_deps() {
mkdir -p $TEMPDIR
for i in zlib serf sqlite-amalgamation apr apr-util gmock-fused; do
for i in zlib serf sqlite-amalgamation py3c apr apr-util; do
if [ -d $i ]; then
echo "Local directory '$i' already exists; the downloaded copy won't be used" >&2
fi
@ -165,6 +156,7 @@ get_deps() {
done
else
get_apr
get_py3c
get_serf
get_zlib
get_sqlite

View File

@ -98,7 +98,7 @@ extern "C" {
*
* An element may appear in any or all branches, and its EID is the same in
* each branch in which the element appears.
*
*
* By definition, an element keeps the same EID for its whole lifetime, even
* if deleted from all branches and later 'resurrected'.
*

View File

@ -207,6 +207,17 @@ svn_client__mtcc_check_path(svn_node_kind_t *kind,
/** Commits all operations stored in @a mtcc as a new revision and destroys
* @a mtcc.
*
* A log message is obtained from the log message callback in the client
* context in @a mtcc.
*
* @a revprop_table (if non-NULL) supplies additional revision properties;
* it may not supply any "svn:*" revision properties.
*
* As with svn_ra_get_commit_editor3(), after the commit has succeeded,
* it will invoke @a commit_callback (if non-NULL) with filled-in
* #svn_commit_info_t *, @a commit_baton, and @a scratch_pool or some subpool
* thereof as arguments.
*
* @since New in 1.9.
*/
svn_error_t *

View File

@ -281,26 +281,6 @@ svn_client__wc_node_get_origin(svn_client__pathrev_t **origin_p,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* Copy the file or directory on URL in some repository to DST_ABSPATH,
* copying node information and properties. Resolve URL using PEG_REV and
* REVISION.
*
* If URL specifies a directory, create the copy using depth DEPTH.
*
* If MAKE_PARENTS is TRUE and DST_ABSPATH doesn't have an added parent
* create missing parent directories
*/
svn_error_t *
svn_client__copy_foreign(const char *url,
const char *dst_abspath,
svn_opt_revision_t *peg_revision,
svn_opt_revision_t *revision,
svn_depth_t depth,
svn_boolean_t make_parents,
svn_boolean_t already_locked,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/* Same as the public svn_client_mergeinfo_log2 API, except for the addition
* of the TARGET_MERGEINFO_CATALOG and RESULT_POOL parameters.
*
@ -341,6 +321,220 @@ svn_client__mergeinfo_log(svn_boolean_t finding_merged,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return a diff processor that will print a Subversion-style
* (not git-style) diff.
*
* @a anchor is optional (may be null), and is the 'anchor' path to prefix
* to the diff-processor paths before displaying.
*
* @a orig_path_1 and @a orig_path_2 are the two main root paths to be
* diffed; each may be a URL, a local WC path or a local unversioned path.
*
* Other arguments are as for svn_client_diff7() etc.
*/
svn_error_t *
svn_client__get_diff_writer_svn(
svn_diff_tree_processor_t **diff_processor,
const char *anchor,
const char *orig_path_1,
const char *orig_path_2,
const apr_array_header_t *options,
const char *relative_to_dir,
svn_boolean_t no_diff_added,
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
svn_boolean_t ignore_properties,
svn_boolean_t properties_only,
svn_boolean_t pretty_print_mergeinfo,
const char *header_encoding,
svn_stream_t *outstream,
svn_stream_t *errstream,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/*** Editor for diff summary ***/
/* Set *DIFF_PROCESSOR to a diff processor that will report a diff summary
to SUMMARIZE_FUNC.
SUMMARIZE_FUNC is called with SUMMARIZE_BATON as parameter by the
created callbacks for each changed item.
*/
svn_error_t *
svn_client__get_diff_summarize_callbacks(
svn_diff_tree_processor_t **diff_processor,
svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Copy a directory tree or a file (according to @a kind) from @a src_url at
* @a src_rev, to @a dst_abspath in a WC.
*
* The caller should be holding a WC write lock that allows @a dst_abspath to
* be created, such as on the parent of @a dst_abspath.
*
* If not same repositories, then remove any svn:mergeinfo property.
*
* Use @a ra_session to fetch the data. The session may point to any URL
* within the source repository.
*
* This API does not process any externals definitions that may be present
* on copied directories.
*/
svn_error_t *
svn_client__repos_to_wc_copy_internal(svn_boolean_t *timestamp_sleep,
svn_node_kind_t kind,
const char *src_url,
svn_revnum_t src_rev,
const char *dst_abspath,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Copy a directory tree or a file (according to @a kind) from @a src_url at
* @a src_rev, to @a dst_abspath in a WC.
*
* The caller should be holding a WC write lock that allows @a dst_abspath to
* be created, such as on the parent of @a dst_abspath.
*
* If not same repositories, then remove any svn:mergeinfo property.
*
* Use @a ra_session to fetch the data. The session may point to a different
* URL after returning.
*
* This API does not process any externals definitions that may be present
* on copied directories.
*/
svn_error_t *
svn_client__repos_to_wc_copy_by_editor(svn_boolean_t *timestamp_sleep,
svn_node_kind_t kind,
const char *src_url,
svn_revnum_t src_rev,
const char *dst_abspath,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Return an editor for applying local modifications to a WC.
*
* Return an editor in @a *editor_p, @a *edit_baton_p that will apply
* local modifications to the WC subdirectory at @a dst_abspath.
*
* The @a path arguments to the editor methods shall be local WC paths,
* relative to @a dst_abspath. The @a copyfrom_path arguments to the
* editor methods shall be URLs.
*
* Send notifications via @a notify_func / @a notify_baton.
* ### INCOMPLETE
*
* @a ra_session is used to fetch the original content for copies.
*
* Ignore changes to non-regular property (entry-props, DAV/WC-props).
*
* Acquire the WC write lock in 'open_root' and release it in
* 'close_edit', in 'abort_edit', or when @a result_pool is cleared.
*/
svn_error_t *
svn_client__wc_editor(const svn_delta_editor_t **editor_p,
void **edit_baton_p,
const char *dst_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/* Return an editor for applying local modifications to a WC.
*
* Like svn_client__wc_editor() but with additional options.
*
* If @a root_dir_add is true, then create and schedule for addition
* the root directory of this edit, else assume it is already a versioned,
* existing directory.
*
* If @a ignore_mergeinfo_changes is true, ignore any incoming changes
* to the 'svn:mergeinfo' property.
*
* If @a manage_wc_write_lock is true, acquire the WC write lock in
* 'open_root' and release it in 'close_edit', in 'abort_edit', or
* when @a result_pool is cleared.
*/
svn_error_t *
svn_client__wc_editor_internal(const svn_delta_editor_t **editor_p,
void **edit_baton_p,
const char *dst_abspath,
svn_boolean_t root_dir_add,
svn_boolean_t ignore_mergeinfo_changes,
svn_boolean_t manage_wc_write_lock,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Send committable changes found in the WC to a delta-editor.
*
* Committable changes are found in TARGETS:DEPTH:CHANGELISTS.
*
* Send the changes to @a editor:@a edit_baton. The @a path arguments
* to the editor methods are URL-paths relative to the URL of
* @a src_wc_abspath.
*
* ### We will presumably need to change this so that the @a path
* arguments to the editor will be local WC relpaths, in order
* to handle switched paths.
*
* The @a copyfrom_path arguments to the editor methods are URLs. As the
* WC does not store copied-from-foreign-repository metadata, the URL will
* be in the same repository as the URL of its parent path.
*
* Compared with svn_client__do_commit(), this (like svn_client_commit6)
* handles:
* - condense targets and find committable paths
* - checking only one repository is involved
*
* Compared with svn_client_commit6(), this does not handle:
* - externals
* - log message
* - revprops
* - checking the commit includes both halves of each local move
* - changing the copy revision of each local move to ~HEAD
* - WC write locks
* - bumping revisions in WC
* - removing locks and changelists in WC
*/
svn_error_t *
svn_client__wc_replay(const char *src_wc_abspath,
const apr_array_header_t *targets,
svn_depth_t depth,
const apr_array_header_t *changelists,
const svn_delta_editor_t *editor,
void *edit_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Copy local modifications from one WC subtree to another.
*
* Find local modifications under @a src_wc_abspath, in the same way as
* for a commit.
*
* Edit the WC at @a dst_wc_abspath, applying those modifications to the
* current working state to produce a new working state.
*
* The source and destination may be in the same WC or in different WCs.
*/
svn_error_t *
svn_client__wc_copy_mods(const char *src_wc_abspath,
const char *dst_wc_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -0,0 +1,498 @@
/**
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*
* @file svn_client_shelf.h
* @brief Subversion's client library: experimental shelving v3
*/
#ifndef SVN_CLIENT_SHELF_H
#define SVN_CLIENT_SHELF_H
#include <apr.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_time.h>
#include "svn_client.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_wc.h"
#include "svn_diff.h"
#include "private/svn_diff_tree.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** Shelving v3, with checkpoints
*
* @defgroup svn_client_shelves_checkpoints Shelves and checkpoints
* @{
*/
/** A shelf.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf_t
{
/* Public fields (read-only for public use) */
const char *name;
int max_version; /**< @deprecated */
/* Private fields */
const char *wc_root_abspath;
const char *shelves_dir;
apr_hash_t *revprops; /**< non-null; allocated in POOL */
svn_client_ctx_t *ctx;
apr_pool_t *pool;
} svn_client__shelf_t;
/** One version of a shelved change-set.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf_version_t
{
/* Public fields (read-only for public use) */
svn_client__shelf_t *shelf;
apr_time_t mtime; /**< time-stamp of this version */
/* Private fields */
const char *files_dir_abspath; /**< abspath of the storage area */
int version_number; /**< version number starting from 1 */
} svn_client__shelf_version_t;
/** Open an existing shelf or create a new shelf.
*
* Create a new shelf (containing no versions) if a shelf named @a name
* is not found.
*
* The shelf should be closed after use by calling svn_client_shelf_close().
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_open_or_create(svn_client__shelf_t **shelf_p,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Open an existing shelf named @a name, or error if it doesn't exist.
*
* The shelf should be closed after use by calling svn_client_shelf_close().
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_open_existing(svn_client__shelf_t **shelf_p,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Close @a shelf.
*
* If @a shelf is NULL, do nothing; otherwise @a shelf must be an open shelf.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_close(svn_client__shelf_t *shelf,
apr_pool_t *scratch_pool);
/** Delete the shelf named @a name, or error if it doesn't exist.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_delete(const char *name,
const char *local_abspath,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Get an editor that, when driven, will store changes in @a shelf_version.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_mods_editor(const svn_delta_editor_t **editor_p,
void **edit_baton_p,
svn_client__shelf_version_t *shelf_version,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Save the local modifications found by @a paths, @a depth,
* @a changelists as a new version of @a shelf.
*
* If any paths are shelved, create a new shelf-version and return the new
* shelf-version in @a *new_version_p, else set @a *new_version_p to null.
* @a new_version_p may be null if that output is not wanted; a new shelf-
* version is still saved and may be found through @a shelf.
*
* @a paths are relative to the CWD, or absolute.
*
* For each successfully shelved path: call @a shelved_func (if not null)
* with @a shelved_baton.
*
* If any paths cannot be shelved: if @a not_shelved_func is given, call
* it with @a not_shelved_baton for each such path, and still create a new
* shelf-version if any paths are shelved.
*
* This function does not revert the changes from the WC; use
* svn_client_shelf_unapply() for that.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_save_new_version3(svn_client__shelf_version_t **new_version_p,
svn_client__shelf_t *shelf,
const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_client_status_func_t shelved_func,
void *shelved_baton,
svn_client_status_func_t not_shelved_func,
void *not_shelved_baton,
apr_pool_t *scratch_pool);
/** Delete all newer versions of @a shelf newer than @a shelf_version.
*
* If @a shelf_version is null, delete all versions of @a shelf. (The
* shelf will still exist, with any log message and other revprops, but
* with no versions in it.)
*
* Leave the shelf's log message and other revprops unchanged.
*
* Any #svn_client__shelf_version_t object that refers to a deleted version
* will become invalid: attempting to use it will give undefined behaviour.
* The given @a shelf_version will remain valid.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_delete_newer_versions(svn_client__shelf_t *shelf,
svn_client__shelf_version_t *shelf_version,
apr_pool_t *scratch_pool);
/** Return in @a shelf_version an existing version of @a shelf, given its
* @a version_number (starting from 1). Error if that version doesn't exist.
*
* There is no need to "close" it after use.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_version_open(svn_client__shelf_version_t **shelf_version_p,
svn_client__shelf_t *shelf,
int version_number,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return in @a shelf_version the newest version of @a shelf.
*
* Set @a shelf_version to null if no versions exist.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_get_newest_version(svn_client__shelf_version_t **shelf_version_p,
svn_client__shelf_t *shelf,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return in @a versions_p an array of (#svn_client__shelf_version_t *)
* containing all versions of @a shelf.
*
* The versions will be in chronological order, oldest to newest.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_get_all_versions(apr_array_header_t **versions_p,
svn_client__shelf_t *shelf,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Apply @a shelf_version to the WC.
*
* If @a dry_run is true, try applying the shelf-version to the WC and
* report the full set of notifications about successes and conflicts,
* but leave the WC untouched.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_apply(svn_client__shelf_version_t *shelf_version,
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
/** Test whether we can successfully apply the changes for @a file_relpath
* in @a shelf_version to the WC.
*
* Set @a *conflict_p to true if the changes conflict with the WC state,
* else to false.
*
* If @a file_relpath is not found in @a shelf_version, set @a *conflict_p
* to FALSE.
*
* @a file_relpath is relative to the WC root.
*
* A conflict means the shelf cannot be applied successfully to the WC
* because the change to be applied is not compatible with the current
* working state of the WC file. Examples are a text conflict, or the
* file does not exist or is a directory, or the shelf is trying to add
* the file but it already exists, or trying to delete it but it does not
* exist.
*
* Return an error only if something is broken, e.g. unable to read data
* from the specified shelf-version.
*
* Leave the WC untouched.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_test_apply_file(svn_boolean_t *conflict_p,
svn_client__shelf_version_t *shelf_version,
const char *file_relpath,
apr_pool_t *scratch_pool);
/** Reverse-apply @a shelf_version to the WC.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_unapply(svn_client__shelf_version_t *shelf_version,
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
/** Send committable changes found in a shelf to a delta-editor.
*
* Push changes from the @a shelf_version subtree at @a top_relpath
* to @a editor : @a edit_baton.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_replay(svn_client__shelf_version_t *shelf_version,
const char *top_relpath,
const svn_delta_editor_t *editor,
void *edit_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool);
/** Set @a *affected_paths to a hash with one entry for each path affected
* by the @a shelf_version.
*
* The hash key is the path of the affected file, relative to the WC root.
*
* (Future possibility: When moves and copies are supported, the hash key
* is the old path and value is the new path.)
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_paths_changed(apr_hash_t **affected_paths,
svn_client__shelf_version_t *shelf_version,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Set @a shelf's revprop @a prop_name to @a prop_val.
*
* This can be used to set or change the shelf's log message
* (property name "svn:log" or #SVN_PROP_REVISION_LOG).
*
* If @a prop_val is NULL, delete the property (if present).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_revprop_set(svn_client__shelf_t *shelf,
const char *prop_name,
const svn_string_t *prop_val,
apr_pool_t *scratch_pool);
/** Set @a shelf's revprops to @a revprop_table.
*
* This deletes all previous revprops.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_revprop_set_all(svn_client__shelf_t *shelf,
apr_hash_t *revprop_table,
apr_pool_t *scratch_pool);
/** Get @a shelf's revprop @a prop_name into @a *prop_val.
*
* If the property is not present, set @a *prop_val to NULL.
*
* This can be used to get the shelf's log message
* (property name "svn:log" or #SVN_PROP_REVISION_LOG).
*
* The lifetime of the result is limited to that of @a shelf and/or
* of @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_revprop_get(svn_string_t **prop_val,
svn_client__shelf_t *shelf,
const char *prop_name,
apr_pool_t *result_pool);
/** Get @a shelf's revprops into @a props.
*
* The lifetime of the result is limited to that of @a shelf and/or
* of @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_revprop_list(apr_hash_t **props,
svn_client__shelf_t *shelf,
apr_pool_t *result_pool);
/** Set the log message in @a shelf to @a log_message.
*
* If @a log_message is null, delete the log message.
*
* Similar to svn_client_shelf_revprop_set(... SVN_PROP_REVISION_LOG ...).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_set_log_message(svn_client__shelf_t *shelf,
const char *log_message,
apr_pool_t *scratch_pool);
/** Get the log message in @a shelf into @a *log_message.
*
* Set @a *log_message to NULL if there is no log message.
*
* Similar to svn_client_shelf_revprop_get(... SVN_PROP_REVISION_LOG ...).
*
* The result is allocated in @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_get_log_message(char **log_message,
svn_client__shelf_t *shelf,
apr_pool_t *result_pool);
/** Information about a shelf.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf_info_t
{
apr_time_t mtime; /**< mtime of the latest change */
} svn_client__shelf_info_t;
/** Set @a *shelf_infos to a hash, keyed by shelf name, of pointers to
* @c svn_client_shelf_info_t structures, one for each shelf in the
* given WC.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_list(apr_hash_t **shelf_infos,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Report the shelved status of all the shelved paths in @a shelf_version
* via @a walk_func(@a walk_baton, ...).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_version_status_walk(svn_client__shelf_version_t *shelf_version,
const char *wc_relpath,
svn_wc_status_func4_t walk_func,
void *walk_baton,
apr_pool_t *scratch_pool);
/** Output the subtree of @a shelf_version rooted at @a shelf_relpath
* as a diff to @a diff_processor.
*
* ### depth and ignore_ancestry are currently ignored.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf_diff(svn_client__shelf_version_t *shelf_version,
const char *shelf_relpath,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
const svn_diff_tree_processor_t *diff_processor,
apr_pool_t *scratch_pool);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_CLIENT_SHELF_H */

View File

@ -0,0 +1,467 @@
/**
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*
* @file svn_client_shelf2.h
* @brief Subversion's client library: experimental shelving v2
*/
#ifndef SVN_CLIENT_SHELF2_H
#define SVN_CLIENT_SHELF2_H
#include <apr.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_time.h>
#include "svn_client.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_wc.h"
#include "svn_diff.h"
#include "private/svn_diff_tree.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** Shelving v2, with checkpoints
*
* @defgroup svn_client_shelves_checkpoints Shelves and checkpoints
* @{
*/
/** A shelf.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf2_t
{
/* Public fields (read-only for public use) */
const char *name;
int max_version; /** @deprecated */
/* Private fields */
const char *wc_root_abspath;
const char *shelves_dir;
apr_hash_t *revprops; /* non-null; allocated in POOL */
svn_client_ctx_t *ctx;
apr_pool_t *pool;
} svn_client__shelf2_t;
/** One version of a shelved change-set.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf2_version_t
{
/* Public fields (read-only for public use) */
svn_client__shelf2_t *shelf;
apr_time_t mtime; /** time-stamp of this version */
/* Private fields */
const char *files_dir_abspath; /** abspath of the storage area */
int version_number; /** version number starting from 1 */
} svn_client__shelf2_version_t;
/** Open an existing shelf or create a new shelf.
*
* Create a new shelf (containing no versions) if a shelf named @a name
* is not found.
*
* The shelf should be closed after use by calling svn_client_shelf_close().
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_open_or_create(svn_client__shelf2_t **shelf_p,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Open an existing shelf named @a name, or error if it doesn't exist.
*
* The shelf should be closed after use by calling svn_client_shelf_close().
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_open_existing(svn_client__shelf2_t **shelf_p,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
/** Close @a shelf.
*
* If @a shelf is NULL, do nothing; otherwise @a shelf must be an open shelf.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_close(svn_client__shelf2_t *shelf,
apr_pool_t *scratch_pool);
/** Delete the shelf named @a name, or error if it doesn't exist.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_delete(const char *name,
const char *local_abspath,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Save the local modifications found by @a paths, @a depth,
* @a changelists as a new version of @a shelf.
*
* If any paths are shelved, create a new shelf-version and return the new
* shelf-version in @a *new_version_p, else set @a *new_version_p to null.
* @a new_version_p may be null if that output is not wanted; a new shelf-
* version is still saved and may be found through @a shelf.
*
* @a paths are relative to the CWD, or absolute.
*
* For each successfully shelved path: call @a shelved_func (if not null)
* with @a shelved_baton.
*
* If any paths cannot be shelved: if @a not_shelved_func is given, call
* it with @a not_shelved_baton for each such path, and still create a new
* shelf-version if any paths are shelved.
*
* This function does not revert the changes from the WC; use
* svn_client_shelf_unapply() for that.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_save_new_version3(svn_client__shelf2_version_t **new_version_p,
svn_client__shelf2_t *shelf,
const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_client_status_func_t shelved_func,
void *shelved_baton,
svn_client_status_func_t not_shelved_func,
void *not_shelved_baton,
apr_pool_t *scratch_pool);
/** Delete all newer versions of @a shelf newer than @a shelf_version.
*
* If @a shelf_version is null, delete all versions of @a shelf. (The
* shelf will still exist, with any log message and other revprops, but
* with no versions in it.)
*
* Leave the shelf's log message and other revprops unchanged.
*
* Any #svn_client_shelf_version_t object that refers to a deleted version
* will become invalid: attempting to use it will give undefined behaviour.
* The given @a shelf_version will remain valid.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_delete_newer_versions(svn_client__shelf2_t *shelf,
svn_client__shelf2_version_t *shelf_version,
apr_pool_t *scratch_pool);
/** Return in @a shelf_version an existing version of @a shelf, given its
* @a version_number. Error if that version doesn't exist.
*
* There is no need to "close" it after use.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_version_open(svn_client__shelf2_version_t **shelf_version_p,
svn_client__shelf2_t *shelf,
int version_number,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return in @a shelf_version the newest version of @a shelf.
*
* Set @a shelf_version to null if no versions exist.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_get_newest_version(svn_client__shelf2_version_t **shelf_version_p,
svn_client__shelf2_t *shelf,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return in @a versions_p an array of (#svn_client_shelf_version_t *)
* containing all versions of @a shelf.
*
* The versions will be in chronological order, oldest to newest.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_get_all_versions(apr_array_header_t **versions_p,
svn_client__shelf2_t *shelf,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Apply @a shelf_version to the WC.
*
* If @a dry_run is true, try applying the shelf-version to the WC and
* report the full set of notifications about successes and conflicts,
* but leave the WC untouched.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_apply(svn_client__shelf2_version_t *shelf_version,
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
/** Test whether we can successfully apply the changes for @a file_relpath
* in @a shelf_version to the WC.
*
* Set @a *conflict_p to true if the changes conflict with the WC state,
* else to false.
*
* If @a file_relpath is not found in @a shelf_version, set @a *conflict_p
* to FALSE.
*
* @a file_relpath is relative to the WC root.
*
* A conflict means the shelf cannot be applied successfully to the WC
* because the change to be applied is not compatible with the current
* working state of the WC file. Examples are a text conflict, or the
* file does not exist or is a directory, or the shelf is trying to add
* the file but it already exists, or trying to delete it but it does not
* exist.
*
* Return an error only if something is broken, e.g. unable to read data
* from the specified shelf-version.
*
* Leave the WC untouched.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_test_apply_file(svn_boolean_t *conflict_p,
svn_client__shelf2_version_t *shelf_version,
const char *file_relpath,
apr_pool_t *scratch_pool);
/** Reverse-apply @a shelf_version to the WC.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_unapply(svn_client__shelf2_version_t *shelf_version,
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
/** Set @a *affected_paths to a hash with one entry for each path affected
* by the @a shelf_version.
*
* The hash key is the path of the affected file, relative to the WC root.
*
* (Future possibility: When moves and copies are supported, the hash key
* is the old path and value is the new path.)
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_paths_changed(apr_hash_t **affected_paths,
svn_client__shelf2_version_t *shelf_version,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Set @a shelf's revprop @a prop_name to @a prop_val.
*
* This can be used to set or change the shelf's log message
* (property name "svn:log" or #SVN_PROP_REVISION_LOG).
*
* If @a prop_val is NULL, delete the property (if present).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_revprop_set(svn_client__shelf2_t *shelf,
const char *prop_name,
const svn_string_t *prop_val,
apr_pool_t *scratch_pool);
/** Set @a shelf's revprops to @a revprop_table.
*
* This deletes all previous revprops.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_revprop_set_all(svn_client__shelf2_t *shelf,
apr_hash_t *revprop_table,
apr_pool_t *scratch_pool);
/** Get @a shelf's revprop @a prop_name into @a *prop_val.
*
* If the property is not present, set @a *prop_val to NULL.
*
* This can be used to get the shelf's log message
* (property name "svn:log" or #SVN_PROP_REVISION_LOG).
*
* The lifetime of the result is limited to that of @a shelf and/or
* of @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_revprop_get(svn_string_t **prop_val,
svn_client__shelf2_t *shelf,
const char *prop_name,
apr_pool_t *result_pool);
/** Get @a shelf's revprops into @a props.
*
* The lifetime of the result is limited to that of @a shelf and/or
* of @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_revprop_list(apr_hash_t **props,
svn_client__shelf2_t *shelf,
apr_pool_t *result_pool);
/** Set the log message in @a shelf to @a log_message.
*
* If @a log_message is null, delete the log message.
*
* Similar to svn_client_shelf_revprop_set(... SVN_PROP_REVISION_LOG ...).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_set_log_message(svn_client__shelf2_t *shelf,
const char *log_message,
apr_pool_t *scratch_pool);
/** Get the log message in @a shelf into @a *log_message.
*
* Set @a *log_message to NULL if there is no log message.
*
* Similar to svn_client_shelf_revprop_get(... SVN_PROP_REVISION_LOG ...).
*
* The result is allocated in @a result_pool.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_get_log_message(char **log_message,
svn_client__shelf2_t *shelf,
apr_pool_t *result_pool);
/** Information about a shelf.
*
* @warning EXPERIMENTAL.
*/
typedef struct svn_client__shelf2_info_t
{
apr_time_t mtime; /* mtime of the latest change */
} svn_client__shelf2_info_t;
/** Set @a *shelf_infos to a hash, keyed by shelf name, of pointers to
* @c svn_client_shelf_info_t structures, one for each shelf in the
* given WC.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_list(apr_hash_t **shelf_infos,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* Report the shelved status of all the shelved paths in SHELF_VERSION
* via WALK_FUNC(WALK_BATON, ...).
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_version_status_walk(svn_client__shelf2_version_t *shelf_version,
const char *wc_relpath,
svn_wc_status_func4_t walk_func,
void *walk_baton,
apr_pool_t *scratch_pool);
/** Output the subtree of @a shelf_version rooted at @a shelf_relpath
* as a diff to @a diff_processor.
*
* ### depth and ignore_ancestry are currently ignored.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__shelf2_diff(svn_client__shelf2_version_t *shelf_version,
const char *shelf_relpath,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
const svn_diff_tree_processor_t *diff_processor,
apr_pool_t *scratch_pool);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_CLIENT_SHELF2_H */

View File

@ -108,12 +108,6 @@ extern "C" {
#define APR_OPENINFO 0x00100000
#endif
#if !APR_VERSION_AT_LEAST(1,4,0)
#ifndef apr_time_from_msec
#define apr_time_from_msec(msec) ((apr_time_t)(msec) * 1000)
#endif
#endif
/**
* APR 1 has volatile qualifier bugs in some atomic prototypes that
* are fixed in APR 2:

View File

@ -321,7 +321,6 @@ svn_diff__tree_processor_create(void *baton,
*/ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
const char *prefix_relpath,
apr_pool_t *result_pool);
/**

View File

@ -0,0 +1,53 @@
/*
* svn_dirent_uri_private.h : private definitions for dirents and URIs
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#ifndef SVN_DIRENT_URI_PRIVATE_H
#define SVN_DIRENT_URI_PRIVATE_H
#include <apr_pools.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Convert @a relpath from the local style to the canonical internal style.
* "Local style" means native path separators and "." for the empty path.
*
* Allocates the results in @a result_pool. Uses @a scratch_pool for
* temporary allocations.
*
* @since New in 1.7 (as svn_relpath__internal_style()).
* @since Name and signature changed in 1.12.
*/
svn_error_t *
svn_relpath__make_internal(const char **internal_style_relpath,
const char *relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_DIRENT_URI_PRIVATE_H */

View File

@ -348,7 +348,7 @@ svn_element__content_t *
svn_element__tree_get(const svn_element__tree_t *tree,
int eid);
svn_error_t *
void
svn_element__tree_set(svn_element__tree_t *tree,
int eid,
const svn_element__content_t *element);

View File

@ -255,22 +255,6 @@ typedef struct svn_fs_fs__stats_t
apr_hash_t *by_extension;
} svn_fs_fs__stats_t;
/* Scan all contents of the repository FS and return statistics in *STATS,
* allocated in RESULT_POOL. Report progress through PROGRESS_FUNC with
* PROGRESS_BATON, if PROGRESS_FUNC is not NULL.
* Use SCRATCH_POOL for temporary allocations.
*/
svn_error_t *
svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats,
svn_fs_t *fs,
svn_fs_progress_notify_func_t progress_func,
void *progress_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* A node-revision ID in FSFS consists of 3 sub-IDs ("parts") that consist
* of a creation REVISION number and some revision- / transaction-local
* counter value (NUMBER). Old-style ID parts use global counter values.
@ -325,33 +309,60 @@ typedef svn_error_t *
void *baton,
apr_pool_t *scratch_pool);
/* Read the P2L index for the rev / pack file containing REVISION in FS.
* For each index entry, invoke CALLBACK_FUNC with CALLBACK_BATON.
* If not NULL, call CANCEL_FUNC with CANCEL_BATON from time to time.
* Use SCRATCH_POOL for temporary allocations.
*/
svn_error_t *
svn_fs_fs__dump_index(svn_fs_t *fs,
svn_revnum_t revision,
svn_fs_fs__dump_index_func_t callback_func,
void *callback_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool);
typedef struct svn_fs_fs__ioctl_get_stats_input_t
{
svn_fs_progress_notify_func_t progress_func;
void *progress_baton;
} svn_fs_fs__ioctl_get_stats_input_t;
typedef struct svn_fs_fs__ioctl_get_stats_output_t
{
svn_fs_fs__stats_t *stats;
} svn_fs_fs__ioctl_get_stats_output_t;
/* Rewrite the respective index information of the rev / pack file in FS
* containing REVISION and use the svn_fs_fs__p2l_entry_t * array ENTRIES
* as the new index contents. Allocate temporaries from SCRATCH_POOL.
*
* Note that this becomes a no-op if ENTRIES is empty. You may use a zero-
* sized empty entry instead.
*/
svn_error_t *
svn_fs_fs__load_index(svn_fs_t *fs,
svn_revnum_t revision,
apr_array_header_t *entries,
apr_pool_t *scratch_pool);
SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_GET_STATS, SVN_FS_TYPE_FSFS, 1000);
typedef struct svn_fs_fs__ioctl_dump_index_input_t
{
svn_revnum_t revision;
svn_fs_fs__dump_index_func_t callback_func;
void *callback_baton;
} svn_fs_fs__ioctl_dump_index_input_t;
SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_DUMP_INDEX, SVN_FS_TYPE_FSFS, 1001);
typedef struct svn_fs_fs__ioctl_load_index_input_t
{
svn_revnum_t revision;
/* Array of svn_fs_fs__p2l_entry_t * entries. */
apr_array_header_t *entries;
} svn_fs_fs__ioctl_load_index_input_t;
SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_LOAD_INDEX, SVN_FS_TYPE_FSFS, 1002);
typedef struct svn_fs_fs__ioctl_revision_size_input_t
{
svn_revnum_t revision;
} svn_fs_fs__ioctl_revision_size_input_t;
typedef struct svn_fs_fs__ioctl_revision_size_output_t
{
apr_off_t rev_size;
} svn_fs_fs__ioctl_revision_size_output_t;
/* See svn_fs_fs__revision_size(). */
SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_REVISION_SIZE, SVN_FS_TYPE_FSFS, 1003);
typedef struct svn_fs_fs__ioctl_build_rep_cache_input_t
{
svn_revnum_t start_rev;
svn_revnum_t end_rev;
svn_fs_progress_notify_func_t progress_func;
void *progress_baton;
} svn_fs_fs__ioctl_build_rep_cache_input_t;
/* See svn_fs_fs__build_rep_cache(). */
SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_BUILD_REP_CACHE, SVN_FS_TYPE_FSFS, 1004);
#ifdef __cplusplus
}

View File

@ -31,6 +31,7 @@
#include "svn_types.h"
#include "svn_repos.h"
#include "svn_delta.h"
#include "svn_editor.h"
#include "svn_config.h"
@ -85,9 +86,11 @@ svn_repos__validate_prop(const char *name,
*
* NAME is used to check that VALUE should be normalized, and if this
* is the case, VALUE is then normalized, allocated from RESULT_POOL.
* If no normalization is required, VALUE will be copied to RESULT_POOL
* unchanged. If NORMALIZED_P is not NULL, and the normalization
* happened, set *NORMALIZED_P to non-zero. If the property is returned
* If no normalization happened, *RESULT_P will be set to VALUE, and
* no copying of the value will occur.
*
* If NORMALIZED_P is not NULL, and the normalization happened,
* set *NORMALIZED_P to non-zero. If the property is returned
* unchanged and NORMALIZED_P is not NULL, then *NORMALIZED_P will be
* set to zero. SCRATCH_POOL will be used for temporary allocations.
*/
@ -296,6 +299,23 @@ svn_repos__dump_headers(svn_stream_t *stream,
svn_repos__dumpfile_headers_t *headers,
apr_pool_t *scratch_pool);
/* Write a magic header record to DUMP_STREAM specifying format version
* VERSION.
*/
svn_error_t *
svn_repos__dump_magic_header_record(svn_stream_t *dump_stream,
int version,
apr_pool_t *pool);
/* Write a UUID record to DUMP_STREAM.
*
* If UUID is NULL then write nothing at all.
*/
svn_error_t *
svn_repos__dump_uuid_header_record(svn_stream_t *dump_stream,
const char *uuid,
apr_pool_t *pool);
/* Write a revision record to DUMP_STREAM for revision REVISION with revision
* properies REVPROPS, creating appropriate headers.
*
@ -349,6 +369,27 @@ svn_repos__dump_node_record(svn_stream_t *dump_stream,
svn_boolean_t content_length_always,
apr_pool_t *scratch_pool);
/**
* Get a dump editor @a editor along with a @a edit_baton allocated in
* @a pool. The editor will write output to @a stream.
*
* @a update_anchor_relpath is the repository relative path of the
* anchor of the update-style drive which will happen on @a *editor;
* if a replay-style drive will instead be used, it should be passed
* as @c NULL.
*
* In contrast to the dump editor used inside svn_repos_dump_fs4(), this
* one supports only deltas mode.
*
* ### TODO: Unify with the dump editor inside svn_repos_dump_fs4().
*/
svn_error_t *
svn_repos__get_dump_editor(const svn_delta_editor_t **editor,
void **edit_baton,
svn_stream_t *stream,
const char *update_anchor_relpath,
apr_pool_t *pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -120,26 +120,29 @@ svn_sort__array_lookup(const apr_array_header_t *array,
* @a insert_index, growing the array and shuffling existing elements along to
* make room.
*
* @note Private. For use by Subversion's own code only.
*/
void
svn_sort__array_insert(apr_array_header_t *array,
const void *new_element,
int insert_index);
/* Remove @a elements_to_delete elements starting at @a delete_index from the
* array @a arr. If @a delete_index is not a valid element of @a arr,
* @a elements_to_delete is not greater than zero, or
* @a delete_index + @a elements_to_delete is greater than @a arr->nelts,
* then do nothing.
* Raise an error if @a insert_index is less than 0 or greater than the length
* of the array.
*
* @note Private. For use by Subversion's own code only.
*/
void
svn_sort__array_delete(apr_array_header_t *arr,
int delete_index,
int elements_to_delete);
svn_error_t *
svn_sort__array_insert2(apr_array_header_t *array,
const void *new_element,
int insert_index);
/* Remove @a elements_to_delete elements starting at @a delete_index from the
* array @a arr.
*
* Raise an error if the indexes to delete extends outside the array bounds
* or if @a elements_to_delete is not greater than zero.
*
* @note Private. For use by Subversion's own code only.
*/
svn_error_t *
svn_sort__array_delete2(apr_array_header_t *arr,
int delete_index,
int elements_to_delete);
/* Reverse the order of elements in @a array, in place.
*
@ -190,7 +193,7 @@ svn_priority_queue__size(svn_priority_queue__t *queue);
/**
* Returns a reference to the first element in the @a queue. The queue
* contents remains unchanged. If the @a queue is empty, #NULL will be
* contents remains unchanged. If the @a queue is empty, NULL will be
* returned.
*/
void *
@ -212,7 +215,7 @@ svn_priority_queue__pop(svn_priority_queue__t *queue);
/**
* Append the new @a element to the @a queue. @a element must neither be
* #NULL nor the first element as returned by #svn_priority_queue__peek.
* NULL nor the first element as returned by #svn_priority_queue__peek.
*/
void
svn_priority_queue__push(svn_priority_queue__t *queue, const void *element);

View File

@ -389,27 +389,27 @@ svn_hash__make(apr_pool_t *pool);
/** Struct that represents a key value pair read from a serialized hash
* representation. There are special cases that can also be represented:
* a #NULL @a key signifies the end of the hash, a #NULL @a val for non-
* a NULL @a key signifies the end of the hash, a NULL @a val for non-
* NULL keys is only possible in incremental mode describes a deletion.
*
* @since New in 1.9.
*/
typedef struct svn_hash__entry_t
{
/** 0-terminated Key. #NULL if this contains no data at all because we
/** 0-terminated Key. NULL if this contains no data at all because we
* encountered the end of the hash. */
char *key;
/** Length of @a key. Must be 0 if @a key is #NULL. */
/** Length of @a key. Must be 0 if @a key is NULL. */
apr_size_t keylen;
/** 0-terminated value stored with the key. If this is #NULL for a
/** 0-terminated value stored with the key. If this is NULL for a
* non-NULL @a key, then this means that the key shall be removed from
* the hash (only used in incremental mode). Must be #NULL if @a key is
* #NULL. */
* the hash (only used in incremental mode). Must be NULL if @a key is
* NULL. */
char *val;
/** Length of @a val. Must be 0 if @a val is #NULL. */
/** Length of @a val. Must be 0 if @a val is NULL. */
apr_size_t vallen;
} svn_hash__entry_t;

View File

@ -348,19 +348,21 @@ svn_wc__get_wcroot(const char **wcroot_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Set @a *dir to the abspath of the directory in which shelved patches
* are stored, which is inside the WC's administrative directory, and ensure
* the directory exists.
/** Set @a *dir to the abspath of the directory in which administrative
* data for experimental features may be stored. This directory is inside
* the WC's administrative directory. Ensure the directory exists.
*
* @a local_abspath is any path in the WC, and is used to find the WC root.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_wc__get_shelves_dir(char **dir,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
svn_wc__get_experimental_dir(char **dir,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* The following are temporary APIs to aid in the transition from wc-1 to
@ -537,7 +539,7 @@ svn_wc__node_get_origin(svn_boolean_t *is_copy,
* If @a base_only is TRUE then only the base node will be examined,
* otherwise the current base or working node will be examined.
*
* If a value is not interesting you can pass #NULL.
* If a value is not interesting you can pass NULL.
*
* If @a local_abspath is not in the working copy, return
* @c SVN_ERR_WC_PATH_NOT_FOUND. Use @a scratch_pool for all temporary
@ -615,6 +617,42 @@ svn_wc__node_get_base(svn_node_kind_t *kind,
apr_pool_t *scratch_pool);
/* Return an array of const char * elements, which represent local absolute
* paths for nodes, within the working copy indicated by WRI_ABSPATH, which
* have a basename matching BASENAME and have node kind KIND.
* If no such nodes exist, return an empty array.
*
* This function returns only paths to nodes which are present in the highest
* layer of the WC. In other words, paths to deleted and/or excluded nodes are
* never returned.
*/
svn_error_t *
svn_wc__find_working_nodes_with_basename(apr_array_header_t **abspaths,
const char *wri_abspath,
const char *basename,
svn_node_kind_t kind,
svn_wc_context_t *wc_ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* Return an array of const char * elements, which represent local absolute
* paths for nodes, within the working copy indicated by WRI_ABSPATH, which
* are copies of REPOS_RELPATH and have node kind KIND.
* If no such nodes exist, return an empty array.
*
* This function returns only paths to nodes which are present in the highest
* layer of the WC. In other words, paths to deleted and/or excluded nodes are
* never returned.
*/
svn_error_t *
svn_wc__find_copies_of_repos_path(apr_array_header_t **abspaths,
const char *wri_abspath,
const char *repos_relpath,
svn_node_kind_t kind,
svn_wc_context_t *wc_ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* Get the working revision of @a local_abspath using @a wc_ctx. If @a
* local_abspath is not in the working copy, return @c
* SVN_ERR_WC_PATH_NOT_FOUND.
@ -1762,7 +1800,7 @@ svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx,
void *notify_baton,
apr_pool_t *scratch_pool);
/**
/**
* Resolve the text conflict at LOCAL_ABSPATH as per CHOICE, and then
* mark the conflict resolved.
* The working copy must already be locked for resolving, e.g. by calling
@ -1779,7 +1817,7 @@ svn_wc__conflict_text_mark_resolved(svn_wc_context_t *wc_ctx,
void *notify_baton,
apr_pool_t *scratch_pool);
/**
/**
* Resolve the conflicted property PROPNAME at LOCAL_ABSPATH as per CHOICE,
* and then mark the conflict resolved. If MERGED_VALUE is not NULL, this is
* the new merged property, used when choosing #svn_wc_conflict_choose_merged.
@ -1810,7 +1848,7 @@ svn_wc__conflict_prop_mark_resolved(svn_wc_context_t *wc_ctx,
*
* The tree conflict at LOCAL_ABSPATH must have the following properties or
* SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE will be returned:
*
*
* operation: svn_wc_operation_update or svn_wc_operation_switch
* local change: svn_wc_conflict_reason_deleted or
* svn_wc_conflict_reason_replaced or
@ -1847,7 +1885,7 @@ svn_wc__conflict_tree_update_break_moved_away(svn_wc_context_t *wc_ctx,
*
* The tree conflict at LOCAL_ABSPATH must have the following properties or
* SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE will be returned:
*
*
* operation: svn_wc_operation_update or svn_wc_operation_switch
* local change: svn_wc_conflict_reason_deleted or
* svn_wc_conflict_reason_replaced
@ -1883,7 +1921,7 @@ svn_wc__conflict_tree_update_raise_moved_away(svn_wc_context_t *wc_ctx,
*
* The tree conflict at LOCAL_ABSPATH must have the following properties or
* SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE will be returned:
*
*
* operation: svn_wc_operation_update or svn_wc_operation_switch
* local change: svn_wc_conflict_reason_moved_away
* incoming change: svn_wc_conflict_action_edit
@ -2044,15 +2082,19 @@ svn_wc__acquire_write_lock_for_resolve(const char **lock_root_abspath,
/* The implemementation of svn_wc_diff6(), but reporting to a diff processor
*
* If ROOT_RELPATH is not NULL, set *ROOT_RELPATH to the target of the diff
* within the diff namespace. ("" or a single path component).
* New mode, when ANCHOR_AT_GIVEN_PATHS is true:
*
* If ROOT_IS_FILE is NOT NULL set it
* the first processor call. (The anchor is LOCAL_ABSPATH or an ancestor of it)
* Anchor the DIFF_PROCESSOR at LOCAL_ABSPATH.
*
* Backward compatibility mode for svn_wc_diff6(),
* when ANCHOR_AT_GIVEN_PATHS is false:
*
* Send diff processor relpaths relative to LOCAL_ABSPATH if it is a
* directory; otherwise, relative to the parent of LOCAL_ABSPATH.
* This matches the "anchor and target" semantics of svn_wc_diff6().
*/
svn_error_t *
svn_wc__diff7(const char **root_relpath,
svn_boolean_t *root_is_dir,
svn_wc__diff7(svn_boolean_t anchor_at_given_paths,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,

View File

@ -500,7 +500,7 @@ typedef struct svn_client_commit_item3_t
* contents in @c incoming_prop_changes->pool, so that it has the
* same lifetime as this data structure.
*
* See http://subversion.tigris.org/issues/show_bug.cgi?id=806 for a
* See https://issues.apache.org/jira/browse/SVN-806 for a
* description of what would happen if the post-commit process
* didn't group these changes together with all other changes to the
* item.
@ -520,7 +520,7 @@ typedef struct svn_client_commit_item3_t
/**
* When processing the commit this contains the relative path for
* the commit session. #NULL until the commit item is preprocessed.
* the commit session. NULL until the commit item is preprocessed.
* @since New in 1.7.
*/
const char *session_relpath;
@ -736,16 +736,11 @@ typedef svn_error_t *(*svn_client_get_commit_log_t)(
* @{
*/
/** Callback type used by svn_client_blame5() to notify the caller
/** Callback type used by svn_client_blame6() to notify the caller
* that line @a line_no of the blamed file was last changed in @a revision
* which has the revision properties @a rev_props, and that the contents were
* @a line.
*
* @a start_revnum and @a end_revnum contain the start and end revision
* number of the entire blame operation, as determined from the repository
* inside svn_client_blame5(). This can be useful for the blame receiver
* to format the blame output.
*
* If svn_client_blame5() was called with @a include_merged_revisions set to
* TRUE, @a merged_revision, @a merged_rev_props and @a merged_path will be
* set, otherwise they will be NULL. @a merged_path will be set to the
@ -758,6 +753,49 @@ typedef svn_error_t *(*svn_client_get_commit_log_t)(
* will be true if the reason there is no blame information is that the line
* was modified locally. In all other cases @a local_change will be false.
*
* Character Encoding and Line Splitting:
*
* It is up to the client to determine the character encoding. The @a line
* content is delivered without any encoding conversion. The line splitting
* is designed to work with ASCII-compatible encodings including UTF-8. Any
* of the byte sequences LF ("\n"), CR ("\n"), CR LF ("\r\n") ends a line
* and is not included in @a line. The @a line content can include all other
* byte values including zero (ASCII NUL).
*
* @note That is how line splitting is done on the final file content, from
* which this callback is driven. It is not entirely clear whether the line
* splitting used to calculate diffs between each revision and assign a
* revision number to each line is exactly compatible with this in all cases.
*
* Blaming files that have <tt>svn:mime-type</tt> set to something other
* than <tt>text/...</tt> requires the @a ignore_mime_type flag to be set to
* true when calling the svn_client_blame6 function.
*
* @since New in 1.12.
*/
typedef svn_error_t *(*svn_client_blame_receiver4_t)(
void *baton,
apr_int64_t line_no,
svn_revnum_t revision,
apr_hash_t *rev_props,
svn_revnum_t merged_revision,
apr_hash_t *merged_rev_props,
const char *merged_path,
const svn_string_t *line,
svn_boolean_t local_change,
apr_pool_t *pool);
/**
* Similar to #svn_client_blame_receiver4_t, but with the @a line parameter
* as a (const char*) instead of an svn_string_t, and the parameters
* @a start_revnum and @a end_revnum contain the start and end revision
* number of the entire blame operation, as resolved from the repository
* inside svn_client_blame6().
*
* @deprecated Provided for backward compatibility with the 1.11 API.
* To replace @a start_revnum and @a end_revnum, see the corresponding
* output parameters in svn_client_blame6().
*
* @since New in 1.7.
*/
typedef svn_error_t *(*svn_client_blame_receiver3_t)(
@ -1547,6 +1585,38 @@ svn_client_switch(svn_revnum_t *result_rev,
/** @} */
/** Callback for svn_client__layout_list()
*
* @warning EXPERIMENTAL.
*/
typedef svn_error_t * (*svn_client__layout_func_t)(
void *layout_baton,
const char *local_abspath,
const char *repos_root_url,
svn_boolean_t not_present,
svn_boolean_t url_changed,
const char *url,
svn_boolean_t revision_changed,
svn_revnum_t revision,
svn_boolean_t depth_changed,
svn_depth_t depth,
apr_pool_t *scratch_pool);
/**
* Describe the layout of the working copy below @a local_abspath to
* the callback @a layout.
*
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client__layout_list(const char *local_abspath,
svn_client__layout_func_t layout,
void *layout_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/**
* @defgroup Add Begin versioning files/directories in a working copy.
*
@ -2888,6 +2958,12 @@ svn_client_log(const apr_array_header_t *targets,
* #SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE) and the client is 1.9.0 or
* newer.
*
* Before the first call to @a receiver, set @a *start_revnum_p and
* @a *end_revnum_p to the start and end revision number of the entire
* blame operation, as resolved from the repository. This can be useful
* for the blame receiver to format the blame output. Any or both of these
* arguments may be @c NULL.
*
* Use @a diff_options to determine how to compare different revisions of the
* target.
*
@ -2896,8 +2972,33 @@ svn_client_log(const apr_array_header_t *targets,
*
* Use @a pool for any temporary allocation.
*
* @since New in 1.12.
*/
svn_error_t *
svn_client_blame6(svn_revnum_t *start_revnum_p,
svn_revnum_t *end_revnum_p,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *start,
const svn_opt_revision_t *end,
const svn_diff_file_options_t *diff_options,
svn_boolean_t ignore_mime_type,
svn_boolean_t include_merged_revisions,
svn_client_blame_receiver4_t receiver,
void *receiver_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/**
* Similar to svn_client_blame6(), but with #svn_client_blame_receiver3_t
* as the receiver.
*
* @deprecated Provided for backwards compatibility with the 1.11 API.
*
* @since New in 1.7.
*/
SVN_DEPRECATED
svn_error_t *
svn_client_blame5(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
@ -2911,9 +3012,8 @@ svn_client_blame5(const char *path_or_url,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/**
* Similar to svn_client_blame5(), but with #svn_client_blame_receiver3_t
* Similar to svn_client_blame5(), but with #svn_client_blame_receiver2_t
* as the receiver.
*
* @deprecated Provided for backwards compatibility with the 1.6 API.
@ -3060,11 +3160,17 @@ svn_client_blame(const char *path_or_url,
* The above two options are mutually exclusive. It is an error to set
* both to TRUE.
*
* If @a pretty_print_mergeinfo is true, then describe 'svn:mergeinfo'
* property changes in a human-readable form that says what changes were
* merged or reverse merged; otherwise (or if the mergeinfo property values
* don't parse correctly) display them just like any other property.
*
* Generated headers are encoded using @a header_encoding.
*
* Diff output will not be generated for binary files, unless @a
* ignore_content_type is TRUE, in which case diffs will be shown
* regardless of the content types.
* If either side has an svn:mime-type property that indicates 'binary'
* content, then if @a ignore_content_type is set, attempt to produce the
* diff in the usual way, otherwise produce a 'GIT binary diff' in git mode
* or print a warning message in non-git mode.
*
* @a diff_options (an array of <tt>const char *</tt>) is used to pass
* additional command line options to the diff processes invoked to compare
@ -3090,8 +3196,39 @@ svn_client_blame(const char *path_or_url,
* @note @a relative_to_dir doesn't affect the path index generated by
* external diff programs.
*
* @since New in 1.11.
*/
svn_error_t *
svn_client_diff7(const apr_array_header_t *diff_options,
const char *path_or_url1,
const svn_opt_revision_t *revision1,
const char *path_or_url2,
const svn_opt_revision_t *revision2,
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t no_diff_added,
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
svn_boolean_t ignore_properties,
svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
svn_boolean_t pretty_print_mergeinfo,
const char *header_encoding,
svn_stream_t *outstream,
svn_stream_t *errstream,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/** Similar to svn_client_diff7(), but with @a pretty_print_mergeinfo
* always passed as @c TRUE.
*
* @deprecated Provided for backward compatibility with the 1.10 API.
* @since New in 1.8.
*/
SVN_DEPRECATED
svn_error_t *
svn_client_diff6(const apr_array_header_t *diff_options,
const char *path_or_url1,
@ -3249,14 +3386,45 @@ svn_client_diff(const apr_array_header_t *diff_options,
* be either a working-copy path or URL.
*
* If @a peg_revision is #svn_opt_revision_unspecified, behave
* identically to svn_client_diff6(), using @a path_or_url for both of that
* identically to svn_client_diff7(), using @a path_or_url for both of that
* function's @a path_or_url1 and @a path_or_url2 arguments.
*
* All other options are handled identically to svn_client_diff6().
* All other options are handled identically to svn_client_diff7().
*
* @since New in 1.8.
*/
svn_error_t *
svn_client_diff_peg7(const apr_array_header_t *diff_options,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *start_revision,
const svn_opt_revision_t *end_revision,
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t no_diff_added,
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
svn_boolean_t ignore_properties,
svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
svn_boolean_t pretty_print_mergeinfo,
const char *header_encoding,
svn_stream_t *outstream,
svn_stream_t *errstream,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/** Similar to svn_client_diff_peg7(), but with @a pretty_print_mergeinfo
* always passed as @c TRUE.
*
* @deprecated Provided for backward compatibility with the 1.7 API.
* @since New in 1.7.
*/
SVN_DEPRECATED
svn_error_t *
svn_client_diff_peg6(const apr_array_header_t *diff_options,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,
@ -3419,7 +3587,7 @@ svn_client_diff_peg(const apr_array_header_t *diff_options,
* Calls @a summarize_func with @a summarize_baton for each difference
* with a #svn_client_diff_summarize_t structure describing the difference.
*
* See svn_client_diff6() for a description of the other parameters.
* See svn_client_diff7() for a description of the other parameters.
*
* @since New in 1.5.
*/
@ -4274,17 +4442,23 @@ svn_client_relocate(const char *dir,
/**
* Restore the pristine version of working copy @a paths,
* effectively undoing any local mods. For each path in @a paths,
* revert it if it is a file. Else if it is a directory, revert
* according to @a depth:
* effectively undoing any local mods. This means returning each
* path's versioned status to 'unmodified' and changing its on-disk
* state to match that.
*
* If an item was in a state of conflict, reverting also marks the
* conflict as resolved. If there are conflict marker files attached
* to the item, these are removed.
*
* @a paths is an array of (const char *) local WC paths.
*
* If @a depth is #svn_depth_empty, revert just the properties on
* the directory; else if #svn_depth_files, revert the properties
* For each path in @a paths, revert it if it is a file. Else if it is
* a directory, revert according to @a depth:
* If @a depth is #svn_depth_empty, revert just
* the directory; else if #svn_depth_files, revert the directory
* and any files immediately under the directory; else if
* #svn_depth_immediates, revert all of the preceding plus
* properties on immediate subdirectories; else if #svn_depth_infinity,
* immediate subdirectories; else if #svn_depth_infinity,
* revert path and everything under it fully recursively.
*
* @a changelists is an array of <tt>const char *</tt> changelist
@ -4296,9 +4470,18 @@ svn_client_relocate(const char *dir,
* If @a clear_changelists is TRUE, then changelist information for the
* paths is cleared while reverting.
*
* If @a metadata_only is TRUE, the files and directories aren't changed
* by the operation. If there are conflict marker files attached to the
* targets these are removed.
* The @a metadata_only and @a added_keep_local options control the
* extent of reverting. If @a metadata_only is TRUE, the working copy
* files are untouched, but if there are conflict marker files attached
* to these files these markers are removed. Otherwise, if
* @a added_keep_local is TRUE, then all items are reverted except an
* item that was scheduled as plain 'add' (not a copy) will not be
* removed from the working copy. Otherwise, all items are reverted and
* their on-disk state changed to match.
*
* Consult the @c SVN_CONFIG_OPTION_USE_COMMIT_TIMES option in @a ctx to
* determine whether or not to revert timestamp to the time of last
* commit ('use-commit-times = yes').
*
* If @a ctx->notify_func2 is non-NULL, then for each item reverted,
* call @a ctx->notify_func2 with @a ctx->notify_baton2 and the path of
@ -4308,9 +4491,29 @@ svn_client_relocate(const char *dir,
* then do not error, just invoke @a ctx->notify_func2 with @a
* ctx->notify_baton2, using notification code #svn_wc_notify_skip.
*
* @since New in 1.9.
* @warning The 'revert' command intentionally and permanently loses
* local modifications.
*
* @since New in 1.11.
*/
svn_error_t *
svn_client_revert4(const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_boolean_t clear_changelists,
svn_boolean_t metadata_only,
svn_boolean_t added_keep_local,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Similar to svn_client_revert4(), but with @a added_keep_local set to
* TRUE.
*
* @since New in 1.9.
* @deprecated Provided for backwards compatibility with the 1.10 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_client_revert3(const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
@ -4427,12 +4630,23 @@ typedef enum svn_client_conflict_option_id_t {
svn_client_conflict_option_incoming_move_dir_merge,
/* Options for local move vs incoming edit on merge. */
svn_client_conflict_option_local_move_file_text_merge
svn_client_conflict_option_local_move_file_text_merge,
svn_client_conflict_option_local_move_dir_merge, /**< @since New in 1.11. */
/* Options for local missing vs incoming edit on merge. */
svn_client_conflict_option_sibling_move_file_text_merge, /**< @since New in 1.11. */
svn_client_conflict_option_sibling_move_dir_merge, /**< @since New in 1.11. */
/* Options for local move vs incoming move on merge. */
svn_client_conflict_option_both_moved_file_merge, /*< @since New in 1.12 */
svn_client_conflict_option_both_moved_file_move_merge, /*< @since New in 1.12 */
svn_client_conflict_option_both_moved_dir_merge, /*< @since New in 1.12 */
svn_client_conflict_option_both_moved_dir_move_merge, /*< @since New in 1.12 */
} svn_client_conflict_option_id_t;
/**
* Set a merged property value on @a option to @a merged_propval.
*
*
* Setting the merged value is required before resolving the property
* conflict using an option with ID svn_client_conflict_option_merged_text.
*
@ -4448,26 +4662,45 @@ svn_client_conflict_option_set_merged_propval(
const svn_string_t *merged_propval);
/**
* Get a list of possible repository paths which can be applied to the
* svn_client_conflict_option_incoming_move_file_text_merge or
* svn_client_conflict_option_incoming_move_dir_merge resolution
* @a option. (If a different option is passed in, this function will
* raise an assertion failure.)
* Get a list of possible repository paths which can be applied to @a option.
*
* In some situations, there can be multiple possible destinations for an
* incoming move. One such situation is where a file was copied and moved
* in the same revision: svn cp a b; svn mv a c; svn commit
* In some situations, there can be multiple possible destinations for a move.
* One such situation is where a file was copied and moved in the same revision:
* svn cp a b; svn mv a c; svn commit
* When this move is merged elsewhere, both b and c will appear as valid move
* destinations to the conflict resolver. To resolve such ambiguity, the client
* may call this function to obtain a list of possible destinations the user
* may choose from.
*
* @a *possible_moved_to_repos_relpaths is set to NULL if the @a option does
* not support multiple move targets. API users may assume that only one option
* among those which can be applied to a conflict supports move targets.
*
* The array is allocated in @a result_pool and will have "const char *"
* elements pointing to strings also allocated in @a result_pool.
* All paths are relpaths, and relative to the repository root.
*
* @see svn_client_conflict_option_set_moved_to_repos_relpath()
* @see svn_client_conflict_option_set_moved_to_repos_relpath2()
* @since New in 1.11.
*/
svn_error_t *
svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
apr_array_header_t **possible_moved_to_repos_relpaths,
svn_client_conflict_option_t *option,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Get a list of possible repository paths which can be applied to the
* svn_client_conflict_option_incoming_move_file_text_merge, or the
* svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
*
* In SVN 1.10, if a different option is passed in, this function will
* raise an assertion failure. Otherwise this function behaves just like
* svn_client_conflict_option_get_moved_to_repos_relpath_candidates2().
*
* @since New in 1.10.
* @deprecated use svn_client_conflict_option_get_moved_to_repos_relpath_candidates2()
*/
svn_error_t *
svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
@ -4477,19 +4710,34 @@ svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
apr_pool_t *scratch_pool);
/**
* Set the preferred moved target repository path for the
* svn_client_conflict_option_incoming_move_file_text_merge or
* svn_client_conflict_option_incoming_move_dir_merge resolution option.
*
* Set the preferred moved target repository path. If @a option is not
* applicable to a moved target repository path, do nothing.
*
* @a preferred_move_target_idx must be a valid index into the list returned
* by svn_client_conflict_option_get_moved_to_repos_relpath_candidates().
*
*
* This function can be called multiple times.
* It affects the output of svn_client_conflict_tree_get_description() and
* svn_client_conflict_option_get_description(). Call these functions again
* to get updated descriptions containing the newly selected move target.
*
* @since New in 1.11.
*/
svn_error_t *
svn_client_conflict_option_set_moved_to_repos_relpath2(
svn_client_conflict_option_t *option,
int preferred_move_target_idx,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/**
* Like svn_client_conflict_option_set_moved_to_repos_relpath2(), except
* that in SVN 1.10 it raises an assertion failure if an option other
* than svn_client_conflict_option_incoming_move_file_text_merge or
* svn_client_conflict_option_incoming_move_dir_merge is passed.
*
* @since New in 1.10.
* @deprecated use svn_client_conflict_option_set_moved_to_repos_relpath2()
*/
svn_error_t *
svn_client_conflict_option_set_moved_to_repos_relpath(
@ -4500,24 +4748,45 @@ svn_client_conflict_option_set_moved_to_repos_relpath(
/**
* Get a list of possible moved-to abspaths in the working copy which can be
* applied to the svn_client_conflict_option_incoming_move_file_text_merge
* or svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
* (If a different option is passed in, this function will raise an assertion
* failure.)
* applied to @a option.
*
* All working copy paths in the returned list correspond to one repository
* path which is be one of the possible destinations of a move operation.
* More than one repository-side move target candidate may exist; call
* svn_client_conflict_option_get_moved_to_repos_relpath_candidates() before
* calling this function to let the user select a repository path first.
* Otherwise, one of the repository-side paths will be selected internally.
*
* @a *possible_moved_to_abspaths is set to NULL if the @a option does not
* support multiple move targets. API users may assume that only one option
* among those which can be applied to a conflict supports move targets.
*
* All paths in the returned list correspond to the repository path which
* is assumed to be the destination of the incoming move operation.
* To support cases where this destination path is ambiguous, the client may
* call svn_client_conflict_option_get_moved_to_repos_relpath_candidates()
* before calling this function to let the user select a repository path first.
*
* If no possible moved-to paths can be found, return an empty array.
* This doesn't mean that no move happened in the repository. It is possible
* that the move destination is outside the scope of the current working copy,
* for example, in which case the conflict must be resolved in some other way.
*
* @see svn_client_conflict_option_set_moved_to_abspath()
* @see svn_client_conflict_option_set_moved_to_abspath2()
* @since New in 1.11.
*/
svn_error_t *
svn_client_conflict_option_get_moved_to_abspath_candidates2(
apr_array_header_t **possible_moved_to_abspaths,
svn_client_conflict_option_t *option,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Get a list of possible moved-to abspaths in the working copy which can be
* svn_client_conflict_option_incoming_move_file_text_merge, or the
* svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
*
* In SVN 1.10, if a different option is passed in, this function will
* raise an assertion failure. Otherwise this function behaves just like
* svn_client_conflict_option_get_moved_to_abspath_candidates2().
*
* @since New in 1.10.
* @deprecated use svn_client_conflict_option_get_moved_to_abspath_candidates2()
*/
svn_error_t *
svn_client_conflict_option_get_moved_to_abspath_candidates(
@ -4527,14 +4796,34 @@ svn_client_conflict_option_get_moved_to_abspath_candidates(
apr_pool_t *scratch_pool);
/**
* Set the preferred moved target abspath for the
* svn_client_conflict_option_incoming_move_file_text_merge or
* svn_client_conflict_option_incoming_move_dir_merge resolution option.
*
* Set the preferred moved target working copy path. If @a option is not
* applicable to a moved target working copy path, do nothing.
*
* @a preferred_move_target_idx must be a valid index into the list
* returned by svn_client_conflict_option_get_moved_to_abspath_candidates().
*
* returned by svn_client_conflict_option_get_moved_to_abspath_candidates2().
*
* This function can be called multiple times.
* It affects the output of svn_client_conflict_tree_get_description() and
* svn_client_conflict_option_get_description(). Call these functions again
* to get updated descriptions containing the newly selected move target.
*
* @since New in 1.11.
*/
svn_error_t *
svn_client_conflict_option_set_moved_to_abspath2(
svn_client_conflict_option_t *option,
int preferred_move_target_idx,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/**
* Like svn_client_conflict_option_set_moved_to_abspath2(), except that
* in SVN 1.10 this function raises an assertion failure if an option
* other than svn_client_conflict_option_incoming_move_file_text_merge or
* svn_client_conflict_option_incoming_move_dir_merge is passed.
*
* @since New in 1.10.
* @deprecated use svn_client_conflict_option_set_moved_to_abspath2()
*/
svn_error_t *
svn_client_conflict_option_set_moved_to_abspath(
@ -4558,7 +4847,7 @@ svn_client_conflict_option_find_by_id(
/**
* Return a conflict for the conflicted path @a local_abspath.
*
*
* @since New in 1.10.
*/
svn_error_t *
@ -4573,7 +4862,7 @@ svn_client_conflict_get(svn_client_conflict_t **conflict,
*
* The lifetime of @a conflict is limited. Its allocation in
* memory will not persist beyond this callback's execution.
*
*
* @since New in 1.10.
*/
typedef svn_error_t *(*svn_client_conflict_walk_func_t)(
@ -4583,15 +4872,15 @@ typedef svn_error_t *(*svn_client_conflict_walk_func_t)(
/**
* Walk all conflicts within the specified @a depth of @a local_abspath.
* Pass each conflict found during the walk to the @conflict_walk_func
* Pass each conflict found during the walk to the @a conflict_walk_func
* callback, along with @a conflict_walk_func_baton.
* Use cancellation and notification support provided by client context @a ctx.
*
*
* This callback may choose to resolve the conflict. If the act of resolving
* a conflict creates new conflicts within the walked working copy (as might
* be the case for some tree conflicts), the callback will be invoked for each
* such new conflict as well.
*
*
* @since New in 1.10.
*/
svn_error_t *
@ -4611,7 +4900,7 @@ svn_client_conflict_walk(const char *local_abspath,
* It contains the names of conflicted properties. If no property conflict
* exists, the array will contain no elements.
*
* @since New in 1.10.
* @since New in 1.10.
*/
svn_error_t *
svn_client_conflict_get_conflicted(svn_boolean_t *text_conflicted,
@ -4794,7 +5083,7 @@ svn_client_conflict_option_get_description(svn_client_conflict_option_t *option,
* Client implementations which aim to avoid excessive interactive prompting
* may wish to try a recommended resolution option before falling back to
* asking the user which option to use.
*
*
* Conflict resolution with a recommended option is not guaranteed to succeed.
* Clients should check for errors when trying to resolve a conflict and fall
* back to other options and/or interactive prompting when the recommended
@ -4812,7 +5101,7 @@ svn_client_conflict_get_recommended_option_id(svn_client_conflict_t *conflict);
* Return the absolute path to the conflicted working copy node described
* by @a conflict.
*
* @since New in 1.10.
* @since New in 1.10.
*/
const char *
svn_client_conflict_get_local_abspath(svn_client_conflict_t *conflict);
@ -4821,7 +5110,7 @@ svn_client_conflict_get_local_abspath(svn_client_conflict_t *conflict);
* Return the operation during which the conflict described by @a
* conflict was recorded.
*
* @since New in 1.10.
* @since New in 1.10.
*/
svn_wc_operation_t
svn_client_conflict_get_operation(svn_client_conflict_t *conflict);
@ -4829,8 +5118,8 @@ svn_client_conflict_get_operation(svn_client_conflict_t *conflict);
/**
* Return the action an update, switch, or merge operation attempted to
* perform on the working copy node described by @a conflict.
*
* @since New in 1.10.
*
* @since New in 1.10.
*/
svn_wc_conflict_action_t
svn_client_conflict_get_incoming_change(svn_client_conflict_t *conflict);
@ -4843,14 +5132,14 @@ svn_client_conflict_get_incoming_change(svn_client_conflict_t *conflict);
* modifications in the working copy. During merge operations it may
* additionally be part of the history of the merge target branch, anywhere
* between the common ancestor revision and the working copy revision.
*
* @since New in 1.10.
*
* @since New in 1.10.
*/
svn_wc_conflict_reason_t
svn_client_conflict_get_local_change(svn_client_conflict_t *conflict);
/**
* Return information about the repository associated with @a conflict.
* Return information about the repository associated with @a conflict.
* In case of a foreign-repository merge this will differ from the
* repository information associated with the merge target working copy.
*
@ -4868,11 +5157,11 @@ svn_client_conflict_get_repos_info(const char **repos_root_url,
* old version of the conflicted node described by @a conflict.
*
* If the repository-relative path is not available, the @a
* *incoming_old_repos_relpath will be set to @c NULL,
* *incoming_old_repos_relpath will be set to @c NULL,
*
* If the peg revision is not available, @a *incoming_old_regrev will be
* set to SVN_INVALID_REVNUM.
*
*
* If the node kind is not available or if the node does not exist at the
* specified path and revision, @a *incoming_old_node_kind will be set to
* svn_node_none.
@ -4881,7 +5170,7 @@ svn_client_conflict_get_repos_info(const char **repos_root_url,
* Any output parameter may be set to @c NULL by the caller to indicate that
* a particular piece of information should not be returned.
*
* In case of tree conflicts, this path@revision does not necessarily exist
* In case of tree conflicts, this "path@revision" does not necessarily exist
* in the repository, and it does not necessarily represent the incoming
* change which is responsible for the occurance of the tree conflict.
* The responsible incoming change is generally located somewhere between
@ -4987,7 +5276,7 @@ svn_client_conflict_prop_get_reject_abspath(svn_client_conflict_t *conflict);
* Return the set of property values involved in the conflict of property
* PROPNAME described by @a conflict. If a property value is unavailable the
* corresponding output argument is set to @c NULL.
*
*
* A 3-way diff of these property values can be generated with
* svn_diff_mem_string_diff3(). A merged version with conflict
* markers can be generated with svn_diff_mem_string_output_merge3().
@ -5055,11 +5344,11 @@ const char *
svn_client_conflict_text_get_mime_type(svn_client_conflict_t *conflict);
/**
* Return absolute paths to the versions of the text-conflicted file
* Return absolute paths to the versions of the text-conflicted file
* described by @a conflict.
*
* If a particular content is not available, it is set to @c NULL.
*
*
* ### Should this be returning svn_stream_t instead of paths?
* @since: New in 1.10.
*/
@ -5330,7 +5619,7 @@ svn_client_copy7(const apr_array_header_t *sources,
/**
* Similar to svn_client_copy7(), but doesn't support meta_data_only
* and cannot pin externals.
*
*
*
* @since New in 1.7.
* @deprecated Provided for backward compatibility with the 1.8 API.
@ -6549,7 +6838,7 @@ svn_client_list2(const char *path_or_url,
/**
* Similar to svn_client_list2(), but with @a recurse instead of @a depth.
* If @a recurse is TRUE, pass #svn_depth_files for @a depth; else
* If @a recurse is FALSE, pass #svn_depth_immediates for @a depth; else
* pass #svn_depth_infinity.
*
* @since New in 1.4.
@ -6714,169 +7003,12 @@ svn_client_cat(svn_stream_t *out,
/** @} end group: cat */
/** Shelving commands
*
* @defgroup svn_client_shelve_funcs Client Shelving Functions
* @{
*/
/** Shelve a change.
*
* Shelve as @a name the local modifications found by @a paths, @a depth,
* @a changelists. Revert the shelved change from the WC unless @a keep_local
* is true.
*
* If @a dry_run is true, don't actually do it.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelve(const char *name,
const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_boolean_t keep_local,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/** Unshelve the shelved change @a name.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
* Rename the shelved patch to add a '.bak' extension unless @a keep is true.
*
* If @a dry_run is true, don't actually do it.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_unshelve(const char *name,
const char *local_abspath,
svn_boolean_t keep,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/** Delete the shelved patch @a name.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* If @a dry_run is true, don't actually do it.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelves_delete(const char *name,
const char *local_abspath,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
/** Information about a shelved patch.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
typedef struct svn_client_shelved_patch_info_t
{
const char *message; /* first line of log message */
const char *patch_path; /* abspath of the patch file */
svn_io_dirent2_t *dirent; /* info about the patch file */
apr_time_t mtime; /* a copy of dirent->mtime */
} svn_client_shelved_patch_info_t;
/** Set @a *shelved_patch_infos to a hash, keyed by patch name, of pointers to
* @c svn_client_shelved_patch_info_t structures.
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelves_list(apr_hash_t **shelved_patch_infos,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Set @a *any_shelved to indicate if there are any shelved changes in this WC.
*
* This shall provide the answer fast, regardless of how many changes
* are stored, unlike svn_client_shelves_list().
*
* ### Initial implementation isn't O(1) fast -- it just calls
* svn_client_shelves_list().
*
* @a local_abspath is any path in the WC and is used to find the WC root.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelves_any(svn_boolean_t *any_shelved,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** Set @a *affected_paths to a hash with one entry for each path affected
* by the shelf @a name. The hash key is the old path and value is
* the new path, both relative to the WC root. The key and value are the
* same except when a path is moved or copied.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelf_get_paths(apr_hash_t **affected_paths,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Set @a *has_changes to indicate whether the shelf @a name
* contains any modifications, in other words if svn_client_shelf_get_paths()
* would return a non-empty set of paths.
*
* @since New in 1.10.
* @warning EXPERIMENTAL.
*/
SVN_EXPERIMENTAL
svn_error_t *
svn_client_shelf_has_changes(svn_boolean_t *has_changes,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/** @} */
/** Changelist commands
*
* @defgroup svn_client_changelist_funcs Client Changelist Functions
* @{
*/
/** Implementation note:
*
* For now, changelists are implemented by scattering the
* associations across multiple .svn/entries files in a working copy.
* However, this client API was written so that we have the option of
* changing the underlying implementation -- we may someday want to
* store changelist definitions in a centralized database.
*/
/**
* Add each path in @a paths (recursing to @a depth as necessary) to
* @a changelist. If a path is already a member of another

View File

@ -44,8 +44,8 @@ extern "C" {
/**************************************************************************
*** ***
*** For a description of the SVN configuration file syntax, see ***
*** your ~/.subversion/README, which is written out automatically by ***
*** svn_config_ensure(). ***
*** your ~/.subversion/README.txt, which is written out automatically ***
*** by svn_config_ensure(). ***
*** ***
**************************************************************************/

View File

@ -495,6 +495,10 @@ svn_txdelta_send_contents(const unsigned char *contents,
* since there's nothing else in the delta application's context to
* supply a path for error messages.)
*
* The @a source stream will NOT be closed. The @a target stream will be
* closed when the window handler is given a null window to signal the
* end of the delta.
*
* @note To avoid lifetime issues, @a error_info is copied into
* @a pool or a subpool thereof.
*/
@ -859,7 +863,7 @@ svn_txdelta_skip_svndiff_window(apr_file_t *file,
* @c apply_textdelta / @c apply_textdelta_stream and @c close_file
* should not refer to a parent directory baton UNLESS the editor has
* taken precautions to allocate it in a pool of the appropriate
* lifetime (the @a dir_pool passed to @c open_directory and
* lifetime (the @a result_pool passed to @c open_directory and
* @c add_directory definitely does not have the proper lifetime).
* In general, it is recommended to simply avoid keeping a parent
* directory baton in a file baton.
@ -1285,24 +1289,47 @@ svn_delta_depth_filter_editor(const svn_delta_editor_t **editor,
/** Callback function type for svn_delta_path_driver().
*
* The handler of this callback is given the callback baton @a
* callback_baton, @a path which is a relpath relative to the
* callback_baton, @a editor and @a edit_baton which represent the
* editor being driven, @a relpath which is a relpath relative to the
* root of the edit, and the @a parent_baton which represents
* path's parent directory as created by the editor passed to
* svn_delta_path_driver().
* @a relpath's parent directory as created by the editor.
*
* If @a path represents a directory, the handler must return a @a
* *dir_baton for @a path, generated from the same editor (so that the
* driver can later close that directory).
* If the handler deletes the node at @a relpath (and does not replace it
* with an added directory) it must set @a *dir_baton to null or leave
* it unchanged.
*
* If, however, @a path represents a file, the handler should NOT
* return any file batons. It can close any opened or added files
* immediately, or delay that close until the end of the edit when
* svn_delta_path_driver() returns.
* If the handler opens (or adds) a directory at @a relpath, it must set
* @a *dir_baton to the directory baton for @a relpath, generated from
* the same editor. The driver will close the directory later.
*
* If the handler opens (or adds) a file at @a relpath, the handler must
* set @a *dir_baton to null or leave it unchanged. The handler must
* either close the file immediately, or delay that close until the end
* of the edit when svn_delta_path_driver() returns.
*
* Finally, if @a parent_baton is @c NULL, then the root of the edit
* is also one of the paths passed to svn_delta_path_driver(). The
* handler of this callback must call the editor's open_root()
* function and return the top-level root dir baton in @a *dir_baton.
*
* @since New in 1.12.
*/
typedef svn_error_t *(*svn_delta_path_driver_cb_func2_t)(
void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *relpath,
apr_pool_t *pool);
/** Like #svn_delta_path_driver_cb_func2_t but without the @a editor and
* @a edit_baton parameters. The user must arrange for the editor to be
* passed through @a callback_baton (if required, which it usually is).
* And @a path could possibly have a '/' prefix instead of being a relpath;
* see the note on svn_delta_path_driver2().
*
* @deprecated Provided for backward compatibility with the 1.11 API.
*/
typedef svn_error_t *(*svn_delta_path_driver_cb_func_t)(
void **dir_baton,
@ -1312,24 +1339,51 @@ typedef svn_error_t *(*svn_delta_path_driver_cb_func_t)(
apr_pool_t *pool);
/** Drive @a editor (with its @a edit_baton) to visit each path in @a paths.
/** Drive @a editor (with its @a edit_baton) to visit each path in @a relpaths.
*
* As each path is hit as part of the editor drive, use
* @a callback_func and @a callback_baton to allow the caller to handle
* the portion of the editor drive related to that path.
*
* Each path in @a paths is a (const char *) relpath, relative
* to the root path of the @a edit. The editor drive will be
* performed in the same order as @a paths. The paths should be sorted
* using something like svn_sort_compare_paths to ensure that a depth-first
* pattern is observed for directory/file baton creation. If @a sort_paths
* Each path in @a relpaths is a (const char *) relpath, relative
* to the root path of the edit. The editor drive will be
* performed in the same order as @a relpaths. The paths should be sorted
* using something like svn_sort_compare_paths() to ensure that each
* directory in the depth-first walk is visited only once. If @a sort_paths
* is set, the function will sort the paths for you. Some callers may need
* further customization of the order (ie. libsvn_delta/compat.c).
*
* If the first target path (after any requested sorting) is @c "" (the
* root of the edit), the callback function will be responsible for
* calling the editor's @c open_root method; otherwise, this function
* will call @c open_root.
*
* Use @a scratch_pool for all necessary allocations.
*
* @since New in 1.8.
* @since New in 1.12.
*/
svn_error_t *
svn_delta_path_driver3(const svn_delta_editor_t *editor,
void *edit_baton,
const apr_array_header_t *relpaths,
svn_boolean_t sort_paths,
svn_delta_path_driver_cb_func2_t callback_func,
void *callback_baton,
apr_pool_t *pool);
/** Like svn_delta_path_driver3() but with a different callback function
* signature.
*
* Optionally, paths in @a paths could have a '/' prefix instead of being
* relpaths. If any of them do, then (since 1.12) ALL paths sent to the
* callback will have a '/' prefix.
*
* @deprecated Provided for backward compatibility with the 1.11 API.
* @since New in 1.8. Before 1.12, paths sent to the callback were the
* exact paths passed in @a paths.
*/
SVN_DEPRECATED
svn_error_t *
svn_delta_path_driver2(const svn_delta_editor_t *editor,
void *edit_baton,
const apr_array_header_t *paths,
@ -1358,6 +1412,80 @@ svn_delta_path_driver(const svn_delta_editor_t *editor,
void *callback_baton,
apr_pool_t *scratch_pool);
/** A state object for the path driver that is obtained from
* svn_delta_path_driver_start() and driven by
* svn_delta_path_driver_step() and svn_delta_path_driver_finish().
*
* @since New in 1.12.
*/
typedef struct svn_delta_path_driver_state_t svn_delta_path_driver_state_t;
/** Return a path driver object that can drive @a editor (with its
* @a edit_baton) to visit a series of paths.
*
* As each path is hit as part of the editor drive, the path driver will
* call @a callback_func and @a callback_baton to allow the caller to handle
* the portion of the editor drive related to that path.
*
* This will not call the editor's open_root method; for that, see
* svn_delta_path_driver_step().
*
* @since New in 1.12.
*/
svn_error_t *
svn_delta_path_driver_start(svn_delta_path_driver_state_t **state_p,
const svn_delta_editor_t *editor,
void *edit_baton,
svn_delta_path_driver_cb_func2_t callback_func,
void *callback_baton,
apr_pool_t *result_pool);
/** Visit @a relpath.
*
* @a state is the object returned by svn_delta_path_driver_start().
*
* @a relpath is a relpath relative to the root path of the edit.
*
* This function uses the editor and the callback that were originally
* supplied to svn_delta_path_driver_start().
*
* This drives the editor in a depth-first order, closing and then opening
* directories if necessary to move from the last visited path to the new
* path, as required by the editor driving rules.
*
* This then calls the callback to allow the caller to handle
* the portion of the editor drive related to that path.
*
* If the first path to visit is @c "" (the root of the edit), the
* callback function will be responsible for calling the editor's
* @c open_root method; otherwise, this function will call @c open_root.
*
* The order of paths to visit should in general be sorted using something
* like svn_sort_compare_paths() to ensure that each directory in the
* depth-first walk is visited only once. Some editors may rely on such a
* restriction.
*
* @since New in 1.12.
*/
svn_error_t *
svn_delta_path_driver_step(svn_delta_path_driver_state_t *state,
const char *relpath,
apr_pool_t *scratch_pool);
/** Finish driving the editor.
*
* @a state is the object returned by svn_delta_path_driver_start().
*
* This drives the editor to close any open directories and then calls
* the editor's @c close_edit method.
*
* @since New in 1.12.
*/
svn_error_t *
svn_delta_path_driver_finish(svn_delta_path_driver_state_t *state,
apr_pool_t *scratch_pool);
/** @} */

View File

@ -711,7 +711,7 @@ svn_diff_file_output_unified(svn_stream_t *output_stream,
* @a conflict_latest to be displayed as conflict markers in the output.
* If @a conflict_original, @a conflict_modified, @a conflict_latest and/or
* @a conflict_separator is @c NULL, a default marker will be displayed.
* @a conflict_style dictates how conflicts are displayed.
* @a conflict_style dictates how conflicts are displayed.
* Uses @a scratch_pool for temporary allocations.
*
* If not @c NULL, call @a cancel_func with @a cancel_baton once or multiple

View File

@ -60,12 +60,14 @@
* form, except:
*
* - @c svn_dirent_canonicalize()
* - @c svn_dirent_canonicalize_safe()
* - @c svn_dirent_is_canonical()
* - @c svn_dirent_internal_style()
* - @c svn_relpath_canonicalize()
* - @c svn_relpath_canonicalize_safe()
* - @c svn_relpath_is_canonical()
* - @c svn_relpath__internal_style()
* - @c svn_uri_canonicalize()
* - @c svn_uri_canonicalize_safe()
* - @c svn_uri_is_canonical()
*
* The Subversion codebase also recognizes some other classes of path:
@ -144,17 +146,47 @@ extern "C" {
#endif /* __cplusplus */
/** Convert @a dirent from the local style to the canonical internal style.
/**
* Convert @a dirent from the local style to the canonical internal style.
* "Local style" means native path separators and "." for the empty path.
*
* Allocate the result in @a result_pool.
*
* @warning This function may call @c abort() if the @a dirent parameter
* is not a valid local-style path.
* Use svn_dirent_internal_style_safe() for tainted input.
*
* @since New in 1.6.
*/
const char *
svn_dirent_internal_style(const char *dirent,
apr_pool_t *result_pool);
/**
* Convert @a dirent from the local style to the canonical internal style
* and return it in @a *internal_style_dirent. "Local style" means native
* path separators and "." for the empty path.
*
* Similar to svn_dirent_internal_style() (which see), but returns an error
* if the @a dirent can not be canonicalized or of the result does not pass
* the svn_dirent_is_canonical() test.
*
* If the function fails and @a non_canonical_result is not @c NULL, the
* result of the failed canonicalization attempt (which may be @c NULL)
* will be returned in @a *non_canonical_result.
*
* Allocates the results in @a result_pool. Uses @a scratch_pool for
* temporary allocations.
*
* @since New in 1.12.
*/
svn_error_t *
svn_dirent_internal_style_safe(const char **internal_style_dirent,
const char **non_canonical_result,
const char *dirent,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Convert @a dirent from the internal style to the local style.
* "Local style" means native path separators and "." for the empty path.
* If the input is not canonical, the output may not be canonical.
@ -167,18 +199,6 @@ const char *
svn_dirent_local_style(const char *dirent,
apr_pool_t *result_pool);
/** Convert @a relpath from the local style to the canonical internal style.
* "Local style" means native path separators and "." for the empty path.
*
* Allocate the result in @a result_pool.
*
* @since New in 1.7.
*/
const char *
svn_relpath__internal_style(const char *relpath,
apr_pool_t *result_pool);
/** Join a base dirent (@a base) with a component (@a component).
*
* If either @a base or @a component is the empty string, then the other
@ -453,7 +473,8 @@ svn_boolean_t
svn_uri_is_root(const char *uri,
apr_size_t len);
/** Return a new dirent like @a dirent, but transformed such that some types
/**
* Return a new dirent like @a dirent, but transformed such that some types
* of dirent specification redundancies are removed.
*
* This involves:
@ -467,14 +488,43 @@ svn_uri_is_root(const char *uri,
*
* Allocate the result in @a result_pool.
*
* @warning This function may call @c abort() if @a dirent can not be
* canonicalized.
* Use svn_dirent_canonicalize_safe() for tainted input.
*
* @since New in 1.6.
*/
const char *
svn_dirent_canonicalize(const char *dirent,
apr_pool_t *result_pool);
/**
* Return a new @a *canonical_dirent like @a dirent, but transformed such
* that some types of dirent specification redundancies are removed.
*
* Similar to svn_dirent_canonicalize() (which see), but returns an error
* if the @a dirent can not be canonicalized or of the result does not pass
* the svn_dirent_is_canonical() test.
*
* If the function fails and @a non_canonical_result is not @c NULL, the
* result of the failed canonicalization attempt (which may be @c NULL)
* will be returned in @a *non_canonical_result.
*
* Allocates the results in @a result_pool. Uses @a scratch_pool for
* temporary allocations.
*
* @since New in 1.12.
*/
svn_error_t *
svn_dirent_canonicalize_safe(const char **canonical_dirent,
const char **non_canonical_result,
const char *dirent,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return a new relpath like @a relpath, but transformed such that some types
/**
* Return a new relpath like @a relpath, but transformed such that some types
* of relpath specification redundancies are removed.
*
* This involves:
@ -486,14 +536,44 @@ svn_dirent_canonicalize(const char *dirent,
*
* Allocate the result in @a result_pool.
*
* @warning This function may call @c abort() if @a relpath can not be
* canonicalized.
* Use svn_relpath_canonicalize_safe() for tainted input.
*
* @since New in 1.7.
*/
const char *
svn_relpath_canonicalize(const char *relpath,
apr_pool_t *result_pool);
/**
* Return a new @a *canonical_relpath like @a relpath, but transformed such
* that some types of relpath specification redundancies are removed.
*
* Similar to svn_relpath_canonicalize() (which see), but returns an error
* if the @a relpath can not be canonicalized or of the result does not
* pass the svn_relpath_is_canonical() test.
*
* If the function fails and @a non_canonical_result is not @c NULL, the
* result of the failed canonicalization attempt (which may be @c NULL)
* will be returned in @a *non_canonical_result.
*
* Allocates the results in @a result_pool. Uses @a scratch_pool for
* temporary allocations.
*
* @since New in 1.12.
*/
/** Return a new uri like @a uri, but transformed such that some types
svn_error_t *
svn_relpath_canonicalize_safe(const char **canonical_relpath,
const char **non_canonical_result,
const char *relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Return a new uri like @a uri, but transformed such that some types
* of uri specification redundancies are removed.
*
* This involves:
@ -510,12 +590,41 @@ svn_relpath_canonicalize(const char *relpath,
*
* Allocate the result in @a result_pool.
*
* @since New in 1.7.
* @warning This function may call @c abort() if @a uri can not be
* canonicalized.
* Use svn_uri_canonicalize_safe() for tainted input.
*
* @since New in 1.7.
*/
const char *
svn_uri_canonicalize(const char *uri,
apr_pool_t *result_pool);
/**
* Return a new @a *canonical_uri like @a uri, but transformed such that
* some types of uri specification redundancies are removed.
*
* Similar to svn_uri_canonicalize() (which see), but returns an error if
* the @a uri can not be canonicalized or of the result does not pass the
* svn_uri_is_canonical() test.
*
* If the function fails and @a non_canonical_result is not @c NULL, the
* result of the failed canonicalization attempt (which may be @c NULL)
* will be returned in @a *non_canonical_result.
*
* Allocates the results in @a result_pool. Uses @a scratch_pool for
* temporary allocations.
*
* @since New in 1.12.
*/
svn_error_t *
svn_uri_canonicalize_safe(const char **canonical_uri,
const char **non_canonical_result,
const char *uri,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** Return @c TRUE iff @a dirent is canonical.
*
* Use @a scratch_pool for temporary allocations.

View File

@ -888,6 +888,21 @@ SVN_ERROR_START
SVN_ERR_FS_CATEGORY_START + 67,
"Content checksums supposedly match but content does not.")
/** @since New in 1.13. */
SVN_ERRDEF(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE,
SVN_ERR_FS_CATEGORY_START + 68,
"Unrecognized filesystem I/O control code")
/** @since New in 1.14. */
SVN_ERRDEF(SVN_ERR_FS_REP_SHARING_NOT_ALLOWED,
SVN_ERR_FS_CATEGORY_START + 69,
"Rep-sharing is not allowed.")
/** @since New in 1.14. */
SVN_ERRDEF(SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED,
SVN_ERR_FS_CATEGORY_START + 70,
"Rep-sharing is not supported.")
/* repos errors */
SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,
@ -1482,6 +1497,11 @@ SVN_ERROR_START
SVN_ERR_MISC_CATEGORY_START + 46,
"LZ4 decompression failed")
/** @since New in 1.12. */
SVN_ERRDEF(SVN_ERR_CANONICALIZATION_FAILED,
SVN_ERR_MISC_CATEGORY_START + 47,
"Could not canonicalize path or URI")
/* command-line client errors */
SVN_ERRDEF(SVN_ERR_CL_ARG_PARSING_ERROR,
@ -1769,7 +1789,7 @@ SVN_ERROR_START
SVN_ERRDEF(SVN_ERR_X509_CERT_VERIFY_FAILED,
SVN_ERR_X509_CATEGORY_START + 19,
"Certficate verification failed")
"Certificate verification failed")
SVN_ERROR_END

View File

@ -1744,7 +1744,7 @@ svn_fs_paths_changed3(svn_fs_path_change_iterator_t **iterator,
*
* Use @a pool for all allocations, including the hash and its values.
*
* @note Retrieving the #node_rev_id element of #svn_fs_path_change2_t may
* @note Retrieving the #svn_fs_path_change2_t.node_rev_id element may
* be expensive in some FS backends.
*
* @since New in 1.6.
@ -1828,9 +1828,9 @@ svn_fs_node_history(svn_fs_history_t **history_p,
* the same as the original. This will happen if the original
* location was an interesting one (where the node was modified, or
* took place in a copy event). This behavior allows looping callers
* to avoid the calling svn_fs_history_location() on the object
* returned by svn_fs_node_history(), and instead go ahead and begin
* calling svn_fs_history_prev().
* to avoid calling svn_fs_history_location() on the object returned
* by svn_fs_node_history(), and instead go ahead and begin calling
* svn_fs_history_prev().
*
* @note This function uses node-id ancestry alone to determine
* modifiedness, and therefore does NOT claim that in any of the
@ -2492,7 +2492,7 @@ svn_fs_file_md5_checksum(unsigned char digest[],
* svn_fs_file_contents(). In that case, the result of reading from
* @a *contents is undefined.
*
* ### @todo kff: I am worried about lifetime issues with this pool vs
* @todo kff: I am worried about lifetime issues with this pool vs
* the trail created farther down the call stack. Trace this function
* to investigate...
*/
@ -3503,6 +3503,54 @@ svn_fs_info_dup(const void *info,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* A structure specifying the filesystem-specific input/output operation.
*
* @see svn_fs_ioctl()
*
* @since New in 1.13.
*/
typedef struct svn_fs_ioctl_code_t
{
const char *fs_type;
int code;
} svn_fs_ioctl_code_t;
/**
* A convenience macro to declare #svn_fs_ioctl_code_t codes.
*
* @since New in 1.13.
*/
#define SVN_FS_DECLARE_IOCTL_CODE(name, fs_type, code) \
static const svn_fs_ioctl_code_t name = { fs_type, code }
/**
* Issue a filesystem-specific input/output operation defined by @a ctlcode
* (usually, a low-level operation which cannot be expressed by other
* filesystem APIs). If @a fs is @c NULL, issue a global operation.
* If @a fs is not @c NULL, issue an operation that is specific to this
* filesystem instance.
*
* If the filesystem cannot handle this ioctl code, return the
* #SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE error.
*
* Allocate the result in @a result_pool, use @a scratch_pool for temporary
* allocations.
*
* @see #svn_fs_ioctl_code_t
*
* @since New in 1.13.
*/
svn_error_t *
svn_fs_ioctl(svn_fs_t *fs,
svn_fs_ioctl_code_t ctlcode,
void *input,
void **output_p,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/** @} */
#ifdef __cplusplus

View File

@ -27,6 +27,8 @@
#ifndef SVN_OPT_H
#define SVN_OPT_H
#include "svn_opt_impl.h"
#include <apr.h>
#include <apr_pools.h>
#include <apr_getopt.h>
@ -69,15 +71,51 @@ typedef svn_error_t *(svn_opt_subcommand_t)(
/** The maximum number of options that can be accepted by a subcommand. */
#define SVN_OPT_MAX_OPTIONS 50
/** The maximum number of paragraphs of help text a subcommand can have.
* @since New in 1.11. */
#define SVN_OPT_MAX_PARAGRAPHS 100
/** Options that have no short option char should use an identifying
* integer equal to or greater than this.
*/
#define SVN_OPT_FIRST_LONGOPT_ID 256
/** One element of a subcommand dispatch table.
*
* @since New in 1.11.
*/
typedef struct svn_opt_subcommand_desc3_t
{
/** The full name of this command. */
const char *name;
/** The function this command invokes. */
svn_opt_subcommand_t *cmd_func;
/** A list of alias names for this command (e.g., 'up' for 'update'). */
const char *aliases[SVN_OPT_MAX_ALIASES];
/** A multi-paragraph string describing this command. */
const char *help[SVN_OPT_MAX_PARAGRAPHS];
/** A list of options accepted by this command. Each value in the
* array is a unique enum (the 2nd field in apr_getopt_option_t)
*/
int valid_options[SVN_OPT_MAX_OPTIONS];
/** A list of option help descriptions, keyed by the option unique enum
* (the 2nd field in apr_getopt_option_t), which override the generic
* descriptions given in an apr_getopt_option_t on a per-subcommand basis.
*/
struct { int optch; const char *desc; } desc_overrides[SVN_OPT_MAX_OPTIONS];
} svn_opt_subcommand_desc3_t;
/** One element of a subcommand dispatch table.
*
* @since New in 1.4.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
typedef struct svn_opt_subcommand_desc2_t
{
@ -139,8 +177,21 @@ typedef struct svn_opt_subcommand_desc_t
* Return the entry in @a table whose name matches @a cmd_name, or @c NULL if
* none. @a cmd_name may be an alias.
*
* @since New in 1.4.
* @since New in 1.11.
*/
const svn_opt_subcommand_desc3_t *
svn_opt_get_canonical_subcommand3(const svn_opt_subcommand_desc3_t *table,
const char *cmd_name);
/**
* Same as svn_opt_get_canonical_subcommand3(), but with a different
* version of the subcommand description table.
*
* @since New in 1.4.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
const svn_opt_subcommand_desc2_t *
svn_opt_get_canonical_subcommand2(const svn_opt_subcommand_desc2_t *table,
const char *cmd_name);
@ -170,9 +221,23 @@ svn_opt_get_canonical_subcommand(const svn_opt_subcommand_desc_t *table,
*
* The returned value may be statically allocated, or allocated in @a pool.
*
* @since New in 1.4.
* @since New in 1.11.
*/
const apr_getopt_option_t *
svn_opt_get_option_from_code3(int code,
const apr_getopt_option_t *option_table,
const svn_opt_subcommand_desc3_t *command,
apr_pool_t *pool);
/**
* Same as svn_opt_get_option_from_code3(), but with a different
* version of the subcommand description table.
*
* @since New in 1.4.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
const apr_getopt_option_t *
svn_opt_get_option_from_code2(int code,
const apr_getopt_option_t *option_table,
const svn_opt_subcommand_desc2_t *command,
@ -198,9 +263,22 @@ svn_opt_get_option_from_code(int code,
* non-NULL, it is a zero-terminated array, and all subcommands take
* the options listed in it.
*
* @since New in 1.5.
* @since New in 1.11.
*/
svn_boolean_t
svn_opt_subcommand_takes_option4(const svn_opt_subcommand_desc3_t *command,
int option_code,
const int *global_options);
/**
* Same as svn_opt_subcommand_takes_option4(), but with a different
* version of the subcommand description table.
*
* @since New in 1.5.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
svn_boolean_t
svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command,
int option_code,
const int *global_options);
@ -235,7 +313,7 @@ svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command,
/**
* Print a generic (not command-specific) usage message to @a stream.
*
* ### @todo Why is @a stream a stdio file instead of an svn stream?
* @todo Why is @a stream a stdio file instead of an svn stream?
*
* If @a header is non-NULL, print @a header followed by a newline. Then
* loop over @a cmd_table printing the usage for each command (getting
@ -244,9 +322,25 @@ svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command,
*
* Use @a pool for temporary allocation.
*
* @since New in 1.4.
* @since New in 1.11.
*/
void
svn_opt_print_generic_help3(const char *header,
const svn_opt_subcommand_desc3_t *cmd_table,
const apr_getopt_option_t *opt_table,
const char *footer,
apr_pool_t *pool,
FILE *stream);
/**
* Same as svn_opt_print_generic_help3(), but with a different
* version of the subcommand description table.
*
* @since New in 1.4.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
void
svn_opt_print_generic_help2(const char *header,
const svn_opt_subcommand_desc2_t *cmd_table,
const apr_getopt_option_t *opt_table,
@ -297,9 +391,24 @@ svn_opt_format_option(const char **string,
* use that second name as an alias for the first name. This additional
* behaviour is new in 1.7.
*
* @since New in 1.5.
* @since New in 1.11.
*/
void
svn_opt_subcommand_help4(const char *subcommand,
const svn_opt_subcommand_desc3_t *table,
const apr_getopt_option_t *options_table,
const int *global_options,
apr_pool_t *pool);
/**
* Same as svn_opt_subcommand_help4(), but with a different
* version of the subcommand description table.
*
* @since New in 1.5.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
void
svn_opt_subcommand_help3(const char *subcommand,
const svn_opt_subcommand_desc2_t *table,
const apr_getopt_option_t *options_table,
@ -336,43 +445,7 @@ svn_opt_subcommand_help(const char *subcommand,
/* Parsing revision and date options. */
/**
* Various ways of specifying revisions.
*
* @note
* In contexts where local mods are relevant, the `working' kind
* refers to the uncommitted "working" revision, which may be modified
* with respect to its base revision. In other contexts, `working'
* should behave the same as `committed' or `current'.
*/
enum svn_opt_revision_kind {
/** No revision information given. */
svn_opt_revision_unspecified,
/** revision given as number */
svn_opt_revision_number,
/** revision given as date */
svn_opt_revision_date,
/** rev of most recent change */
svn_opt_revision_committed,
/** (rev of most recent change) - 1 */
svn_opt_revision_previous,
/** .svn/entries current revision */
svn_opt_revision_base,
/** current, plus local mods */
svn_opt_revision_working,
/** repository youngest */
svn_opt_revision_head
/* please update svn_opt__revision_to_string() when extending this enum */
};
/* NOTE: svn_opt_revision_kind is defined in svn_opt_impl.h */
/**
* A revision value, which can be specified as a number or a date.
@ -700,9 +773,30 @@ svn_opt_parse_path(svn_opt_revision_t *rev,
* --version flag *and* subcommand arguments on a help command line.
* The logic for handling such a situation should be in one place.
*
* @since New in 1.8.
* @since New in 1.11.
*/
svn_error_t *
svn_opt_print_help5(apr_getopt_t *os,
const char *pgm_name,
svn_boolean_t print_version,
svn_boolean_t quiet,
svn_boolean_t verbose,
const char *version_footer,
const char *header,
const svn_opt_subcommand_desc3_t *cmd_table,
const apr_getopt_option_t *option_table,
const int *global_options,
const char *footer,
apr_pool_t *pool);
/**
* Same as svn_opt_print_help5(), but with a different
* version of the subcommand description table.
*
* @since New in 1.8.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_opt_print_help4(apr_getopt_t *os,
const char *pgm_name,

View File

@ -0,0 +1,86 @@
/**
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*
* @file svn_opt_impl.h
* @brief Option and argument parsing for Subversion command lines
* (common implementation)
*
* @warning This is a @b private implementation-specific header file.
* User code should include @ref svn_opt.h instead.
*/
/* NOTE:
* This file *must not* include or depend on any other header except
* the C standard library headers.
*/
#ifndef SVN_OPT_IMPL_H
#define SVN_OPT_IMPL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Various ways of specifying revisions.
*
* @note
* In contexts where local mods are relevant, the `working' kind
* refers to the uncommitted "working" revision, which may be modified
* with respect to its base revision. In other contexts, `working'
* should behave the same as `committed' or `current'.
*/
/* NOTE: Update svnxx/revision.hpp when changing this enum. */
enum svn_opt_revision_kind {
/** No revision information given. */
svn_opt_revision_unspecified,
/** revision given as number */
svn_opt_revision_number,
/** revision given as date */
svn_opt_revision_date,
/** rev of most recent change */
svn_opt_revision_committed,
/** (rev of most recent change) - 1 */
svn_opt_revision_previous,
/** .svn/entries current revision */
svn_opt_revision_base,
/** current, plus local mods */
svn_opt_revision_working,
/** repository youngest */
svn_opt_revision_head
/* please update svn_opt__revision_to_string() when extending this enum */
};
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_OPT_IMPL_H */

View File

@ -415,19 +415,26 @@ svn_prop_name_is_valid(const char *prop_name);
/** Describes external items to check out into this directory.
*
* The format is a series of lines, each in the following format:
* [-r REV] URL[@PEG] LOCALPATH
*
* [-r REV] URL[@PEG] LOCALPATH
*
* LOCALPATH is relative to the directory having this property.
* REV pins the external to revision REV.
* URL may be a full URL or a relative URL starting with one of:
* ../ to the parent directory of the extracted external
* ^/ to the repository root
* / to the server root
* // to the URL scheme
*
* ../ to the parent directory of the extracted external
* ^/ to the repository root
* / to the server root
* // to the URL scheme
*
* The following format is supported for interoperability with
* Subversion 1.4 and earlier clients:
* LOCALPATH [-r PEG] URL
*
* LOCALPATH [-r PEG] URL
*
* The ambiguous format 'relative_path relative_path' is taken as
* 'relative_url relative_path' with peg revision support.
*
* Lines starting with a '#' character are ignored.
*/
#define SVN_PROP_EXTERNALS SVN_PROP_PREFIX "externals"

View File

@ -65,7 +65,7 @@ svn_ra_version(void);
* @a close_baton as appropriate.
*
* @a path is relative to the "root" of the session, defined by the
* @a repos_URL passed to svn_ra_open4() vtable call.
* @a repos_URL passed to svn_ra_open5() vtable call.
*
* @a name is the name of the property to fetch. If the property is present,
* then it is returned in @a value. Otherwise, @a *value is set to @c NULL.
@ -229,7 +229,7 @@ typedef void (*svn_ra_progress_notify_func_t)(apr_off_t progress,
*
* @a revision is the target revision number of the received replay report.
*
* @a editor and @a edit_baton should provided by the callback implementation.
* @a *editor and @a *edit_baton should provided by the callback implementation.
*
* @a replay_baton is the baton as originally passed to replay_range.
*
@ -253,7 +253,7 @@ typedef svn_error_t *(*svn_ra_replay_revstart_callback_t)(
*
* @a revision is the target revision number of the received replay report.
*
* @a editor and @a edit_baton should provided by the callback implementation.
* @a editor and @a edit_baton are the values provided by the REVSTART callback.
*
* @a replay_baton is the baton as originally passed to replay_range.
*
@ -369,7 +369,7 @@ typedef struct svn_ra_reporter3_t
* implementor should assume the directory has no entries or props.
*
* This will *override* any previous set_path() calls made on parent
* paths. @a path is relative to the URL specified in svn_ra_open4().
* paths. @a path is relative to the URL specified in svn_ra_open5().
*
* If @a lock_token is non-NULL, it is the lock token for @a path in the WC.
*
@ -520,7 +520,7 @@ typedef struct svn_ra_reporter_t
/** A collection of callbacks implemented by libsvn_client which allows
* an RA layer to "pull" information from the client application, or
* possibly store information. libsvn_client passes this vtable to
* svn_ra_open4().
* svn_ra_open5().
*
* Each routine takes a @a callback_baton originally provided with the
* vtable.
@ -555,9 +555,9 @@ typedef struct svn_ra_callbacks2_t
/** Fetch working copy properties.
*
*<pre> ### we might have a problem if the RA layer ever wants a property
* ### that corresponds to a different revision of the file than
* ### what is in the WC. we'll cross that bridge one day...</pre>
* @note we might have a problem if the RA layer ever wants a property
* that corresponds to a different revision of the file than
* what is in the WC. we'll cross that bridge one day...
*/
svn_ra_get_wc_prop_func_t get_wc_prop;
@ -710,6 +710,14 @@ typedef struct svn_ra_session_t svn_ra_session_t;
* within the new repository root URL that @a repos_URL pointed to within
* the old repository root URL.
*
* If @a redirect_url is not NULL and a @corrected_url is returned, then
* @a redirect_url contains a non-canonicalized version of @a corrected_url,
* as communicated in the network protocol used by the RA provider.
* THe @a redirect_url should be used for to detect redirection loops.
* Canonicalization may change the protocol-level URL in a way that
* makes detection of redirect loops impossible in some cases since URLs which
* are different at the protocol layer could map to the same canonicalized URL.
*
* Return @c SVN_ERR_RA_UUID_MISMATCH if @a uuid is non-NULL and not equal
* to the UUID of the repository at @c repos_URL.
*
@ -728,9 +736,27 @@ typedef struct svn_ra_session_t svn_ra_session_t;
*
* @see svn_client_open_ra_session().
*
* @since New in 1.7.
* @since New in 1.14.
*/
svn_error_t *
svn_ra_open5(svn_ra_session_t **session_p,
const char **corrected_url,
const char **redirect_url,
const char *repos_URL,
const char *uuid,
const svn_ra_callbacks2_t *callbacks,
void *callback_baton,
apr_hash_t *config,
apr_pool_t *pool);
/** Similar to svn_ra_open5(), but with @a redirect_url always passed
* as @c NULL.
*
* @since New in 1.7.
* @deprecated Provided for backward compatibility with the 1.13 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_ra_open4(svn_ra_session_t **session_p,
const char **corrected_url,
const char *repos_URL,
@ -1857,7 +1883,7 @@ svn_ra_get_location_segments(svn_ra_session_t *session,
* @note Prior to Subversion 1.9, this function may request delta handlers
* from @a handler even for empty text deltas. Starting with 1.9, the
* delta handler / baton return arguments passed to @a handler will be
* #NULL unless there is an actual difference in the file contents between
* NULL unless there is an actual difference in the file contents between
* the current and the previous call.
*
* @since New in 1.5.

View File

@ -201,7 +201,7 @@ typedef svn_error_t *(*svn_ra_svn_edit_callback)(void *baton);
* If @a max_out is not 0, error out and close the connection whenever more
* than @a max_out bytes have been send as response to some command.
*
* @note The limits enforced may vary slightly by +/- the I/O buffer size.
* @note The limits enforced may vary slightly by +/- the I/O buffer size.
*
* @note If @a out_stream is an wrapped apr_file_t* the backing file will be
* used for some operations.

View File

@ -679,7 +679,7 @@ svn_repos_fs_type(svn_repos_t *repos,
* The optional @a cancel_func callback will be invoked with
* @a cancel_baton as usual to allow the user to preempt this potentially
* lengthy operation.
*
*
* Use @a scratch_pool for temporary allocations.
*
* @since New in 1.9.
@ -861,7 +861,7 @@ typedef svn_error_t *(*svn_repos_freeze_func_t)(void *baton, apr_pool_t *pool);
* @since New in 1.8.
*/
svn_error_t *
svn_repos_freeze(apr_array_header_t *paths,
svn_repos_freeze(const apr_array_header_t *paths,
svn_repos_freeze_func_t freeze_func,
void *freeze_baton,
apr_pool_t *pool);
@ -1036,7 +1036,10 @@ svn_repos_hooks_setenv(svn_repos_t *repos,
*
* @a send_copyfrom_args instructs the driver to send 'copyfrom'
* arguments to the editor's add_file() and add_directory() methods,
* whenever it deems feasible.
* and therefore to send their content as deltas against the copy source,
* whenever it deems feasible. The implementation only does so for
* add_file(), and only when the file itself is the copy root (not when
* the file is part of a copied subtree).
*
* Use @a authz_read_func and @a authz_read_baton (if not @c NULL) to
* avoid sending data through @a editor/@a edit_baton which is not
@ -2404,7 +2407,7 @@ svn_repos_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
* @note Prior to Subversion 1.9, this function may request delta handlers
* from @a handler even for empty text deltas. Starting with 1.9, the
* delta handler / baton return arguments passed to @a handler will be
* #NULL unless there is an actual difference in the file contents between
* NULL unless there is an actual difference in the file contents between
* the current and the previous call.
*
* @since New in 1.5.
@ -3357,7 +3360,7 @@ svn_repos_dump_fs4(svn_repos_t *repos,
apr_pool_t *pool);
/**
* Similar to svn_repos_dump_fs4(), but with @a include_revprops and
* Similar to svn_repos_dump_fs4(), but with @a include_revprops and
* @a include_changes both set to @c TRUE and @a filter_func and
* @a filter_baton set to @c NULL.
*
@ -3803,7 +3806,7 @@ typedef struct svn_repos_parse_fns3_t
*
* @since New in 1.8.
* @since Starting in 1.10, @a parse_fns may contain #NULL pointers for
* @since Starting in 1.10, @a parse_fns may contain NULL pointers for
* those callbacks that the caller is not interested in.
*/
svn_error_t *
@ -4143,6 +4146,19 @@ typedef struct svn_authz_t svn_authz_t;
svn_error_t *
svn_repos_authz_initialize(apr_pool_t *pool);
/**
* Callback for reporting authz file parsing warnings.
*
* The implementation may use @a scratch_pool for temporary
* allocations but should not assume that the lifetime of that pool
* persists past the callback invocation.
*
* The implementation @e must @e not clear @a error.
*/
typedef void (*svn_repos_authz_warning_func_t)(void *baton,
const svn_error_t *error,
apr_pool_t *scratch_pool);
/**
* Read authz configuration data from @a path (a dirent, an absolute file url
* or a registry path) into @a *authz_p, allocated in @a pool.
@ -4161,9 +4177,32 @@ svn_repos_authz_initialize(apr_pool_t *pool);
* repository instance. Otherwise, set it to NULL and the repositories will
* be opened as needed.
*
* @since New in 1.10.
* If the @a warning_func callback is not @c NULL, it is called
* (with @a warning_baton) to report non-fatal warnings emitted by
* the parser.
*
* @since New in 1.12.
*/
svn_error_t *
svn_repos_authz_read4(svn_authz_t **authz_p,
const char *path,
const char *groups_path,
svn_boolean_t must_exist,
svn_repos_t *repos_hint,
svn_repos_authz_warning_func_t warning_func,
void *warning_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Similar to svn_repos_authz_read3(), but with @a warning_func and
* @a warning_baton set to @c NULL.
*
* @since New in 1.10.
* @deprecated Provided for backward compatibility with the 1.11 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_repos_authz_read3(svn_authz_t **authz_p,
const char *path,
const char *groups_path,
@ -4203,13 +4242,36 @@ svn_repos_authz_read(svn_authz_t **authz_p,
/**
* Read authz configuration data from @a stream into @a *authz_p,
* allocated in @a pool.
* allocated in @a result_pool.
*
* If @a groups_stream is set, use the global groups parsed from it.
*
* @since New in 1.8.
* If the @a warning_func callback is not @c NULL, it is called
* (with @a warning_baton) to report non-fatal warnings emitted by
* the parser.
*
* Uses @a scratch_pool for temporary aloocations.
*
* @since New in 1.12.
*/
svn_error_t *
svn_repos_authz_parse2(svn_authz_t **authz_p,
svn_stream_t *stream,
svn_stream_t *groups_stream,
svn_repos_authz_warning_func_t warning_func,
void *warning_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/**
* Similar to svn_repos_authz_parse2(), but with @a warning_func and
* @a warning_baton set to @c NULL.
*
* @since New in 1.8.
* @deprecated Provided for backward compatibility with the 1.11 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_repos_authz_parse(svn_authz_t **authz_p,
svn_stream_t *stream,
svn_stream_t *groups_stream,

View File

@ -38,14 +38,21 @@ extern "C" {
/** Convert @a when to a <tt>const char *</tt> representation allocated
* in @a pool. Use svn_time_from_cstring() for the reverse
* conversion.
* in @a pool.
*
* @see svn_time_from_cstring() for the reverse conversion.
*/
const char *
svn_time_to_cstring(apr_time_t when,
apr_pool_t *pool);
/** Convert @a data to an @c apr_time_t @a when.
*
* @see svn_time_to_cstring() for the reverse conversion.
*
* @deprecated Also accepts a format that was used before Subversion 0.14.
* See implementation for details. Use of this format is deprecated.
*
* Use @a pool for temporary memory allocation.
*/
svn_error_t *

View File

@ -27,6 +27,8 @@
#ifndef SVN_TYPES_H
#define SVN_TYPES_H
#include "svn_types_impl.h"
/* ### this should go away, but it causes too much breakage right now */
#include <stdlib.h>
#include <limits.h> /* for ULONG_MAX */
@ -246,35 +248,6 @@ typedef struct svn_version_t svn_version_t;
/** @} */
/** @defgroup apr_hash_utilities APR Hash Table Helpers
* These functions enable the caller to dereference an APR hash table index
* without type casts or temporary variables.
*
* These functions are provided by APR itself from version 1.5.
* Definitions are provided here for when using older versions of APR.
* @{
*/
#if !APR_VERSION_AT_LEAST(1, 5, 0)
/** Return the key of the hash table entry indexed by @a hi. */
const void *
apr_hash_this_key(apr_hash_index_t *hi);
/** Return the key length of the hash table entry indexed by @a hi. */
apr_ssize_t
apr_hash_this_key_len(apr_hash_index_t *hi);
/** Return the value of the hash table entry indexed by @a hi. */
void *
apr_hash_this_val(apr_hash_index_t *hi);
#endif
/** @} */
/** On Windows, APR_STATUS_IS_ENOTDIR includes several kinds of
* invalid-pathname error but not ERROR_INVALID_NAME, so we include it.
@ -303,28 +276,7 @@ apr_hash_this_val(apr_hash_index_t *hi);
/** The various types of nodes in the Subversion filesystem. */
typedef enum svn_node_kind_t
{
/** absent */
svn_node_none,
/** regular file */
svn_node_file,
/** directory */
svn_node_dir,
/** something's here, but we don't know what */
svn_node_unknown,
/**
* symbolic link
* @note This value is not currently used by the public API.
* @since New in 1.8.
*/
svn_node_symlink
} svn_node_kind_t;
/* NOTE: svn_node_kind_t is defined in svn_types_impl.h */
/** Return a constant string expressing @a kind as an English word, e.g.,
* "file", "dir", etc. The string is not localized, as it may be used for
@ -346,23 +298,7 @@ svn_node_kind_t
svn_node_kind_from_word(const char *word);
/** Generic three-state property to represent an unknown value for values
* that are just like booleans. The values have been set deliberately to
* make tristates disjoint from #svn_boolean_t.
*
* @note It is unsafe to use apr_pcalloc() to allocate these, since '0' is
* not a valid value.
*
* @since New in 1.7. */
typedef enum svn_tristate_t
{
/** state known to be false (the constant does not evaulate to false) */
svn_tristate_false = 2,
/** state known to be true */
svn_tristate_true,
/** state could be true or false */
svn_tristate_unknown
} svn_tristate_t;
/* NOTE: svn_tristate_t is defined in svn_types_impl.h */
/** Return a constant string "true", "false" or NULL representing the value of
* @a tristate.
@ -422,15 +358,11 @@ svn_tristate__from_word(const char * word);
/** A revision number. */
typedef long int svn_revnum_t;
/* NOTE: svn_revnum_t and SVN_INVALID_REVNUM are defined in svn_types_impl.h */
/** Valid revision numbers begin at 0 */
#define SVN_IS_VALID_REVNUM(n) ((n) >= 0)
/** The 'official' invalid revision num */
#define SVN_INVALID_REVNUM ((svn_revnum_t) -1)
/** Not really invalid...just unimportant -- one day, this can be its
* own unique value, for now, just make it the same as
* #SVN_INVALID_REVNUM.
@ -494,55 +426,7 @@ enum svn_recurse_kind
svn_recursive
};
/** The concept of depth for directories.
*
* @note This is similar to, but not exactly the same as, the WebDAV
* and LDAP concepts of depth.
*
* @since New in 1.5.
*/
typedef enum svn_depth_t
{
/* The order of these depths is important: the higher the number,
the deeper it descends. This allows us to compare two depths
numerically to decide which should govern. */
/** Depth undetermined or ignored. In some contexts, this means the
client should choose an appropriate default depth. The server
will generally treat it as #svn_depth_infinity. */
svn_depth_unknown = -2,
/** Exclude (i.e., don't descend into) directory D.
@note In Subversion 1.5, svn_depth_exclude is *not* supported
anywhere in the client-side (libsvn_wc/libsvn_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
svn_depth_exclude behavior, once we get a chance to implement
client-side support for svn_depth_exclude.)
*/
svn_depth_exclude = -1,
/** Just the named directory D, no entries. Updates will not pull in
any files or subdirectories not already present. */
svn_depth_empty = 0,
/** D + its file children, but not subdirs. Updates will pull in any
files not already present, but not subdirectories. */
svn_depth_files = 1,
/** D + immediate children (D and its entries). Updates will pull in
any files or subdirectories not already present; those
subdirectories' this_dir entries will have depth-empty. */
svn_depth_immediates = 2,
/** D + all descendants (full recursion from D). Updates will pull
in any files or subdirectories not already present; those
subdirectories' this_dir entries will have depth-infinity.
Equivalent to the pre-1.5 default update behavior. */
svn_depth_infinity = 3
} svn_depth_t;
/* NOTE: svn_depth_t is defined in svn_types_impl.h */
/** Return a constant string expressing @a depth as an English word,
* e.g., "infinity", "immediates", etc. The string is not localized,

View File

@ -0,0 +1,157 @@
/**
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*
* @file svn_types_impl.h
* @brief Subversion's data types (common implementation)
*
* @warning This is a @b private implementation-specific header file.
* User code should include @ref svn_types.h instead.
*/
/* NOTE:
* This file *must not* include or depend on any other header except
* the C standard library headers.
*/
#ifndef SVN_TYPES_IMPL_H
#define SVN_TYPES_IMPL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef DOXYGEN
/* Forward declaration of the error object. */
struct svn_error_t;
#endif
/** The various types of nodes in the Subversion filesystem. */
typedef enum svn_node_kind_t
{
/** absent */
svn_node_none,
/** regular file */
svn_node_file,
/** directory */
svn_node_dir,
/** something's here, but we don't know what */
svn_node_unknown,
/**
* symbolic link
* @note This value is not currently used by the public API.
* @since New in 1.8.
*/
svn_node_symlink
} svn_node_kind_t;
/** Generic three-state property to represent an unknown value for values
* that are just like booleans. The values have been set deliberately to
* make tristates disjoint from #svn_boolean_t.
*
* @note It is unsafe to use apr_pcalloc() to allocate these, since '0' is
* not a valid value.
*
* @since New in 1.7. */
/* NOTE: Update svnxx/tristate.hpp when changing this enum. */
typedef enum svn_tristate_t
{
/** state known to be false (the constant does not evaulate to false) */
svn_tristate_false = 2,
/** state known to be true */
svn_tristate_true,
/** state could be true or false */
svn_tristate_unknown
} svn_tristate_t;
/** A revision number. */
/* NOTE: Update svnxx/revision.hpp when changing this typedef. */
typedef long int svn_revnum_t;
/** The 'official' invalid revision number. */
/* NOTE: Update svnxx/revision.hpp when changing this definition. */
#define SVN_INVALID_REVNUM ((svn_revnum_t) -1)
/** The concept of depth for directories.
*
* @note This is similar to, but not exactly the same as, the WebDAV
* and LDAP concepts of depth.
*
* @since New in 1.5.
*/
/* NOTE: Update svnxx/depth.hpp when changing this enum. */
typedef enum svn_depth_t
{
/* The order of these depths is important: the higher the number,
the deeper it descends. This allows us to compare two depths
numerically to decide which should govern. */
/** Depth undetermined or ignored. In some contexts, this means the
client should choose an appropriate default depth. The server
will generally treat it as #svn_depth_infinity. */
svn_depth_unknown = -2,
/** Exclude (i.e., don't descend into) directory D.
@note In Subversion 1.5, svn_depth_exclude is *not* supported
anywhere in the client-side (libsvn_wc/libsvn_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
svn_depth_exclude behavior, once we get a chance to implement
client-side support for svn_depth_exclude.)
*/
svn_depth_exclude = -1,
/** Just the named directory D, no entries. Updates will not pull in
any files or subdirectories not already present. */
svn_depth_empty = 0,
/** D + its file children, but not subdirs. Updates will pull in any
files not already present, but not subdirectories. */
svn_depth_files = 1,
/** D + immediate children (D and its entries). Updates will pull in
any files or subdirectories not already present; those
subdirectories' this_dir entries will have depth-empty. */
svn_depth_immediates = 2,
/** D + all descendants (full recursion from D). Updates will pull
in any files or subdirectories not already present; those
subdirectories' this_dir entries will have depth-infinity.
Equivalent to the pre-1.5 default update behavior. */
svn_depth_infinity = 3
} svn_depth_t;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_TYPES_IMPL_H */

View File

@ -212,7 +212,7 @@ svn_utf_cstring_from_utf8_ex(const char **dest,
* so when we can detect that at configure time, things will change.
* Also, this should (?) be moved to apr/apu eventually.
*
* See http://subversion.tigris.org/issues/show_bug.cgi?id=807 for
* See https://issues.apache.org/jira/browse/SVN-807 for
* details.
*/
const char *

View File

@ -61,7 +61,7 @@ extern "C" {
* Modify when new functionality is added or new interfaces are
* defined, but all changes are backward compatible.
*/
#define SVN_VER_MINOR 10
#define SVN_VER_MINOR 14
/**
* Patch number.
@ -93,7 +93,7 @@ extern "C" {
*
* Always change this at the same time as SVN_VER_NUMTAG.
*/
#define SVN_VER_TAG " (r1827917)"
#define SVN_VER_TAG " (r1876290)"
/** Number tag: a string describing the version.
@ -117,7 +117,7 @@ extern "C" {
* file version. Its value remains 0 in the repository except in release
* tags where it is the revision from which the tag was created.
*/
#define SVN_VER_REVISION 1827917
#define SVN_VER_REVISION 1876290
/* Version strings composed from the above definitions. */

View File

@ -7602,9 +7602,14 @@ svn_wc_relocate(const char *path,
* If @a clear_changelists is TRUE, then changelist information for the
* paths is cleared.
*
* If @a metadata_only is TRUE, the working copy files are untouched, but
* if there are conflict marker files attached to these files these
* markers are removed.
* The @a metadata_only and @a added_keep_local options control the
* extent of reverting. If @a metadata_only is TRUE, the working copy
* files are untouched, but if there are conflict marker files attached
* to these files these markers are removed. Otherwise, if
* @a added_keep_local is TRUE, then all items are reverted except an
* item that was scheduled as plain 'add' (not a copy) will not be
* removed from the working copy. Otherwise, all items are reverted and
* their on-disk state changed to match.
*
* If @a cancel_func is non-NULL, call it with @a cancel_baton at
* various points during the reversion process. If it returns an
@ -7622,9 +7627,31 @@ svn_wc_relocate(const char *path,
* If @a path is not under version control, return the error
* #SVN_ERR_UNVERSIONED_RESOURCE.
*
* @since New in 1.9.
* @since New in 1.11.
*/
svn_error_t *
svn_wc_revert6(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
const apr_array_header_t *changelist_filter,
svn_boolean_t clear_changelists,
svn_boolean_t metadata_only,
svn_boolean_t added_keep_local,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool);
/** Similar to svn_wc_revert6() but with @a added_keep_local always
* set to TRUE.
*
* @since New in 1.9.
* @deprecated Provided for backward compatibility with the 1.10 API.
*/
SVN_DEPRECATED
svn_error_t *
svn_wc_revert5(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,

View File

@ -118,10 +118,12 @@ password_get_gnome_keyring(svn_boolean_t *done,
{
GError *gerror = NULL;
gchar *gpassword;
*done = FALSE;
if (!available_collection(non_interactive, pool))
return SVN_NO_ERROR;
gpassword = secret_password_lookup_sync(SECRET_SCHEMA_COMPAT_NETWORK, NULL,
&gerror,
"domain", realmstring,
@ -129,6 +131,7 @@ password_get_gnome_keyring(svn_boolean_t *done,
NULL);
if (gerror)
{
/* ### TODO: return or log the error? */
g_error_free(gerror);
}
else if (gpassword)
@ -137,7 +140,7 @@ password_get_gnome_keyring(svn_boolean_t *done,
g_free(gpassword);
*done = TRUE;
}
return SVN_NO_ERROR;
}
@ -155,7 +158,9 @@ password_set_gnome_keyring(svn_boolean_t *done,
{
GError *gerror = NULL;
gboolean gstatus;
*done = FALSE;
if (!available_collection(non_interactive, pool))
return SVN_NO_ERROR;
@ -170,13 +175,14 @@ password_set_gnome_keyring(svn_boolean_t *done,
NULL);
if (gerror)
{
/* ### TODO: return or log the error? */
g_error_free(gerror);
}
else if (gstatus)
{
*done = TRUE;
}
return SVN_NO_ERROR;
}

View File

@ -6,7 +6,7 @@ includedir=@includedir@
Name: libsvn_auth_gnome_keyring
Description: Subversion GNOME Keyring Library
Version: @PACKAGE_VERSION@
Requires: apr-@SVN_APR_MAJOR_VERSION@ gnome-keyring-1
Requires.private: libsvn_subr
Libs: -L${libdir} -lsvn_auth_gnome_keyring
Cflags: -I${includedir}
Requires: apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_subr, @SVN_GNOME_KEYRING_PCLIBS@
Libs: -L${libdir} -lsvn_auth_gnome_keyring-1
Cflags: -I${includedir}/subversion-1

View File

@ -227,10 +227,10 @@ kwallet_password_get(svn_boolean_t *done,
KLocalizedString::setApplicationDomain("subversion"); /* translation domain */
/* componentName appears in KDE GUI prompts */
KAboutData aboutData(QStringLiteral("subversion"), /* componentName */
KAboutData aboutData(QString("subversion"), /* componentName */
i18n(get_application_name(parameters,
pool)), /* displayName */
QStringLiteral(SVN_VER_NUMBER));
QString(SVN_VER_NUMBER));
KAboutData::setApplicationData(aboutData);
#else
KCmdLineArgs::init(q_argc, q_argv,
@ -309,10 +309,10 @@ kwallet_password_set(svn_boolean_t *done,
KLocalizedString::setApplicationDomain("subversion"); /* translation domain */
/* componentName appears in KDE GUI prompts */
KAboutData aboutData(QStringLiteral("subversion"), /* componentName */
KAboutData aboutData(QString("subversion"), /* componentName */
i18n(get_application_name(parameters,
pool)), /* displayName */
QStringLiteral(SVN_VER_NUMBER));
QString(SVN_VER_NUMBER));
KAboutData::setApplicationData(aboutData);
#else
KCmdLineArgs::init(q_argc, q_argv,

View File

@ -6,7 +6,7 @@ includedir=@includedir@
Name: libsvn_auth_kwallet
Description: Subversion KWallet Library
Version: @PACKAGE_VERSION@
Requires: apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_subr
Libs: -L${libdir} -lsvn_auth_kwallet @SVN_KWALLET_LIBS@
Cflags: -I${includedir}
Requires: apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_subr
Libs: -L${libdir} -lsvn_auth_kwallet-1 @SVN_KWALLET_LIBS@
Cflags: -I${includedir}/subversion-1

View File

@ -983,12 +983,13 @@ svn_client_add5(const char *path,
static svn_error_t *
path_driver_cb_func(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *path,
apr_pool_t *pool)
{
const svn_delta_editor_t *editor = callback_baton;
SVN_ERR(svn_path_check_valid(path, pool));
return editor->add_directory(path, parent_baton, NULL,
SVN_INVALID_REVNUM, pool, dir_baton);
@ -1177,8 +1178,8 @@ mkdir_urls(const apr_array_header_t *urls,
/* Call the path-based editor driver. */
err = svn_error_trace(
svn_delta_path_driver2(editor, edit_baton, targets, TRUE,
path_driver_cb_func, (void *)editor, pool));
svn_delta_path_driver3(editor, edit_baton, targets, TRUE,
path_driver_cb_func, NULL, pool));
if (err)
{

View File

@ -456,7 +456,7 @@ file_rev_handler(void *baton, const char *path, svn_revnum_t revnum,
SVN_ERR_CLIENT_IS_BINARY_FILE, NULL,
_("Cannot calculate blame information for binary file '%s'"),
(svn_path_is_url(frb->target)
? frb->target
? frb->target
: svn_dirent_local_style(frb->target, pool)));
}
}
@ -553,7 +553,7 @@ file_rev_handler(void *baton, const char *path, svn_revnum_t revnum,
|| frb->include_merged_revisions);
/* The file existed before start_rev; generate no blame info for
lines from this revision (or before).
lines from this revision (or before).
This revision specifies the state as it was at the start revision */
@ -656,14 +656,16 @@ normalize_blames(struct blame_chain *chain,
}
svn_error_t *
svn_client_blame5(const char *target,
svn_client_blame6(svn_revnum_t *start_revnum_p,
svn_revnum_t *end_revnum_p,
const char *target,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *start,
const svn_opt_revision_t *end,
const svn_diff_file_options_t *diff_options,
svn_boolean_t ignore_mime_type,
svn_boolean_t include_merged_revisions,
svn_client_blame_receiver3_t receiver,
svn_client_blame_receiver4_t receiver,
void *receiver_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@ -696,10 +698,13 @@ svn_client_blame5(const char *target,
SVN_ERR(svn_client__get_revision_number(&start_revnum, NULL, ctx->wc_ctx,
target_abspath_or_url, ra_session,
start, pool));
if (start_revnum_p)
*start_revnum_p = start_revnum;
SVN_ERR(svn_client__get_revision_number(&end_revnum, NULL, ctx->wc_ctx,
target_abspath_or_url, ra_session,
end, pool));
if (end_revnum_p)
*end_revnum_p = end_revnum;
{
svn_client__pathrev_t *loc;
@ -734,7 +739,7 @@ svn_client_blame5(const char *target,
mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
}
else
else
{
const svn_string_t *value;
@ -941,18 +946,21 @@ svn_client_blame5(const char *target,
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
if (!eof || sb->len)
{
svn_string_t line;
line.data = sb->data;
line.len = sb->len;
if (walk->rev)
SVN_ERR(receiver(receiver_baton, start_revnum, end_revnum,
SVN_ERR(receiver(receiver_baton,
line_no, walk->rev->revision,
walk->rev->rev_props, merged_rev,
merged_rev_props, merged_path,
sb->data, FALSE, iterpool));
&line, FALSE, iterpool));
else
SVN_ERR(receiver(receiver_baton, start_revnum, end_revnum,
SVN_ERR(receiver(receiver_baton,
line_no, SVN_INVALID_REVNUM,
NULL, SVN_INVALID_REVNUM,
NULL, NULL,
sb->data, TRUE, iterpool));
&line, TRUE, iterpool));
}
if (eof) break;
}

View File

@ -682,34 +682,6 @@ svn_client__get_diff_editor2(const svn_delta_editor_t **editor,
/* ---------------------------------------------------------------- */
/*** Editor for diff summary ***/
/* Set *DIFF_PROCESSOR to a diff processor that will report a diff summary
to SUMMARIZE_FUNC.
P_ROOT_RELPATH will return a pointer to a string that must be set to
the root of the operation before the processor is called.
ORIGINAL_PATH specifies the original path and will be used with
**ANCHOR_PATH to create paths as the user originally provided them
to the diff function.
SUMMARIZE_FUNC is called with SUMMARIZE_BATON as parameter by the
created callbacks for each changed item.
*/
svn_error_t *
svn_client__get_diff_summarize_callbacks(
const svn_diff_tree_processor_t **diff_processor,
const char ***p_root_relpath,
svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
const char *original_target,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* ---------------------------------------------------------------- */
/*** Copy Stuff ***/
/* This structure is used to associate a specific copy or move SRC with a
@ -754,40 +726,23 @@ typedef struct svn_client__copy_pair_t
/*** Commit Stuff ***/
/* WARNING: This is all new, untested, un-peer-reviewed conceptual
stuff.
/* The "Harvest Committables" System
The day that 'svn switch' came into existence, our old commit
crawler (svn_wc_crawl_local_mods) became obsolete. It relied far
too heavily on the on-disk hierarchy of files and directories, and
simply had no way to support disjoint working copy trees or nest
working copies. The primary reason for this is that commit
process, in order to guarantee atomicity, is a single drive of a
The commit process requires, per repository, a single drive of a
commit editor which is based not on working copy paths, but on
URLs. With the completion of 'svn switch', it became all too
likely that the on-disk working copy hierarchy would no longer be
guaranteed to map to a similar in-repository hierarchy.
URLs. The on-disk working copy hierarchy does not, in general,
map to a similar in-repository hierarchy, due to switched subtrees
and disjoint working copies.
Aside from this new brokenness of the old system, an unrelated
feature request had cropped up -- the ability to know in advance of
your commit, exactly what would be committed (so that log messages
could be initially populated with this information). Since the old
crawler discovered commit candidates while in the process of
committing, it was impossible to harvest this information upfront.
As a workaround, svn_wc_statuses() was used to stat the whole
working copy for changes before the commit started...and then the
commit would again stat the whole tree for changes.
Enter the new system.
Also we wish to know exactly what would be committed, in advance of
the commit, so that a log message editor can be initially populated
with this information.
The primary goal of this system is very straightforward: harvest
all commit candidate information up front, and cache enough info in
the process to use this to drive a URL-sorted commit.
*** END-OF-KNOWLEDGE ***
The prototypes below are still in development. In general, the
idea is that commit-y processes ('svn mkdir URL', 'svn delete URL',
The idea is that commit-y processes ('svn mkdir URL', 'svn delete URL',
'svn commit', 'svn copy WC_PATH URL', 'svn copy URL1 URL2', 'svn
move URL1 URL2', others?) generate the cached commit candidate
information, and hand this information off to a consumer which is
@ -844,7 +799,7 @@ typedef svn_error_t *(*svn_client__check_url_kind_t)(void *baton,
- if the candidate has a lock token, add it to the LOCK_TOKENS hash.
- if the candidate is a directory scheduled for deletion, crawl
the directories children recursively for any lock tokens and
the directory's children recursively for any lock tokens and
add them to the LOCK_TOKENS array.
At the successful return of this function, COMMITTABLES will point
@ -915,6 +870,18 @@ svn_client__condense_commit_items(const char **base_url,
apr_array_header_t *commit_items,
apr_pool_t *pool);
/* Rewrite the COMMIT_ITEMS array to be sorted by URL.
Rewrite the items' URLs to be relative to BASE_URL.
COMMIT_ITEMS is an array of (svn_client_commit_item3_t *) items.
Afterwards, some of the items in COMMIT_ITEMS may contain data
allocated in POOL. */
svn_error_t *
svn_client__condense_commit_items2(const char *base_url,
apr_array_header_t *commit_items,
apr_pool_t *pool);
/* Commit the items in the COMMIT_ITEMS array using EDITOR/EDIT_BATON
to describe the committed local mods. Prior to this call,
COMMIT_ITEMS should have been run through (and BASE_URL generated
@ -1129,24 +1096,26 @@ svn_client__resolve_conflicts(svn_boolean_t *conflicts_remain,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
/* Produce a diff with depth DEPTH between two files or two directories at
* LEFT_ABSPATH1 and RIGHT_ABSPATH, using the provided diff callbacks to
* show changes in files. The files and directories involved may be part of
* a working copy or they may be unversioned. For versioned files, show
* property changes, too.
/* Produce a diff with depth DEPTH between the file or directory at
* LEFT_ABSPATH and the file or directory at RIGHT_ABSPATH, reporting
* differences to DIFF_PROCESSOR.
*
* If ANCHOR_ABSPATH is not null, set it to the anchor of the diff before
* the first processor call. (The anchor is LEFT_ABSPATH or an ancestor of it)
* The files and directories involved may be part of a working copy or
* they may be unversioned. For versioned files, show property changes,
* too.
*
* No copy or move information is reported to the diff processor.
*
* Anchor the DIFF_PROCESSOR at the requested diff targets (LEFT_ABSPATH,
* RIGHT_ABSPATH). As any children reached by recursion are matched by
* name, a diff processor relpath applies equally to both sides of the diff.
*/
svn_error_t *
svn_client__arbitrary_nodes_diff(const char **root_relpath,
svn_boolean_t *root_is_dir,
const char *left_abspath,
svn_client__arbitrary_nodes_diff(const char *left_abspath,
const char *right_abspath,
svn_depth_t depth,
const svn_diff_tree_processor_t *diff_processor,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);

View File

@ -500,6 +500,129 @@ append_externals_as_explicit_targets(apr_array_header_t *rel_targets,
return SVN_NO_ERROR;
}
/* Crawl the working copy for commit items.
*/
static svn_error_t *
harvest_committables(apr_array_header_t **commit_items_p,
apr_hash_t **committables_by_path_p,
apr_hash_t **lock_tokens,
const char *base_dir_abspath,
const apr_array_header_t *targets,
int depth_empty_start,
svn_depth_t depth,
svn_boolean_t just_locked,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
struct check_url_kind_baton cukb;
svn_client__committables_t *committables;
apr_hash_index_t *hi;
/* Prepare for when we have a copy containing not-present nodes. */
cukb.pool = scratch_pool;
cukb.session = NULL; /* ### Can we somehow reuse session? */
cukb.repos_root_url = NULL;
cukb.ctx = ctx;
SVN_ERR(svn_client__harvest_committables(&committables, lock_tokens,
base_dir_abspath, targets,
depth_empty_start, depth,
just_locked,
changelists,
check_url_kind, &cukb,
ctx, result_pool, scratch_pool));
if (apr_hash_count(committables->by_repository) == 0)
{
*commit_items_p = NULL;
return SVN_NO_ERROR; /* Nothing to do */
}
else if (apr_hash_count(committables->by_repository) > 1)
{
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Commit can only commit to a single repository at a time.\n"
"Are all targets part of the same working copy?"));
}
hi = apr_hash_first(scratch_pool, committables->by_repository);
*commit_items_p = apr_hash_this_val(hi);
if (committables_by_path_p)
*committables_by_path_p = committables->by_path;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__wc_replay(const char *src_wc_abspath,
const apr_array_header_t *targets,
svn_depth_t depth,
const apr_array_header_t *changelists,
const svn_delta_editor_t *editor,
void *edit_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *base_abspath;
apr_array_header_t *rel_targets;
apr_hash_t *lock_tokens;
apr_array_header_t *commit_items;
svn_client__pathrev_t *base;
const char *base_url;
svn_wc_notify_func2_t saved_notify_func;
void *saved_notify_baton;
/* Condense the target list. This makes all targets absolute. */
SVN_ERR(svn_dirent_condense_targets(&base_abspath, &rel_targets, targets,
FALSE, pool, pool));
/* No targets means nothing to commit, so just return. */
if (base_abspath == NULL)
return SVN_NO_ERROR;
SVN_ERR_ASSERT(rel_targets != NULL);
/* If we calculated only a base and no relative targets, this
must mean that we are being asked to commit (effectively) a
single path. */
if (rel_targets->nelts == 0)
APR_ARRAY_PUSH(rel_targets, const char *) = "";
/* Crawl the working copy for commit items. */
SVN_ERR(harvest_committables(&commit_items, NULL /*committables_by_path_p*/,
&lock_tokens,
base_abspath, rel_targets,
-1 /*depth_empty_start*/,
depth,
FALSE /*just_locked*/,
changelists,
ctx, pool, pool));
if (!commit_items)
{
return SVN_NO_ERROR;
}
SVN_ERR(svn_client__wc_node_get_base(&base,
src_wc_abspath, ctx->wc_ctx, pool, pool));
base_url = base->url;
/* Sort our COMMIT_ITEMS by URL and find their relative URL-paths. */
SVN_ERR(svn_client__condense_commit_items2(base_url, commit_items, pool));
saved_notify_func = ctx->notify_func2;
saved_notify_baton = ctx->notify_baton2;
ctx->notify_func2 = notify_func;
ctx->notify_baton2 = notify_baton;
/* BASE_URL is only used here in notifications & errors */
SVN_ERR(svn_client__do_commit(base_url, commit_items,
editor, edit_baton,
NULL /*notify_prefix*/, NULL /*sha1_checksums*/,
ctx, pool, pool));
ctx->notify_func2 = saved_notify_func;
ctx->notify_baton2 = saved_notify_baton;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_commit6(const apr_array_header_t *targets,
svn_depth_t depth,
@ -525,7 +648,7 @@ svn_client_commit6(const apr_array_header_t *targets,
apr_array_header_t *rel_targets;
apr_array_header_t *lock_targets;
apr_array_header_t *locks_obtained;
svn_client__committables_t *committables;
apr_hash_t *committables_by_path;
apr_hash_t *lock_tokens;
apr_hash_t *sha1_checksums;
apr_array_header_t *commit_items;
@ -615,55 +738,27 @@ svn_client_commit6(const apr_array_header_t *targets,
pool);
/* Crawl the working copy for commit items. */
{
struct check_url_kind_baton cukb;
/* Prepare for when we have a copy containing not-present nodes. */
cukb.pool = iterpool;
cukb.session = NULL; /* ### Can we somehow reuse session? */
cukb.repos_root_url = NULL;
cukb.ctx = ctx;
cmt_err = svn_error_trace(
svn_client__harvest_committables(&committables,
&lock_tokens,
base_abspath,
rel_targets,
depth_empty_after,
depth,
! keep_locks,
changelists,
check_url_kind,
&cukb,
ctx,
pool,
iterpool));
svn_pool_clear(iterpool);
}
cmt_err = svn_error_trace(
harvest_committables(&commit_items, &committables_by_path,
&lock_tokens,
base_abspath,
rel_targets,
depth_empty_after,
depth,
! keep_locks,
changelists,
ctx,
pool,
iterpool));
svn_pool_clear(iterpool);
if (cmt_err)
goto cleanup;
if (apr_hash_count(committables->by_repository) == 0)
if (!commit_items)
{
goto cleanup; /* Nothing to do */
}
else if (apr_hash_count(committables->by_repository) > 1)
{
cmt_err = svn_error_create(
SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Commit can only commit to a single repository at a time.\n"
"Are all targets part of the same working copy?"));
goto cleanup;
}
{
apr_hash_index_t *hi = apr_hash_first(iterpool,
committables->by_repository);
commit_items = apr_hash_this_val(hi);
}
/* If our array of targets contains only locks (and no actual file
or prop modifications), then we return here to avoid committing a
@ -713,7 +808,7 @@ svn_client_commit6(const apr_array_header_t *targets,
if (moved_from_abspath && delete_op_root_abspath)
{
svn_client_commit_item3_t *delete_half =
svn_hash_gets(committables->by_path, delete_op_root_abspath);
svn_hash_gets(committables_by_path, delete_op_root_abspath);
if (!delete_half)
{
@ -769,7 +864,7 @@ svn_client_commit6(const apr_array_header_t *targets,
if (moved_to_abspath && copy_op_root_abspath &&
strcmp(moved_to_abspath, copy_op_root_abspath) == 0 &&
svn_hash_gets(committables->by_path, copy_op_root_abspath)
svn_hash_gets(committables_by_path, copy_op_root_abspath)
== NULL)
{
cmt_err = svn_error_createf(

View File

@ -1392,6 +1392,29 @@ sort_commit_item_urls(const void *a, const void *b)
}
svn_error_t *
svn_client__condense_commit_items2(const char *base_url,
apr_array_header_t *commit_items,
apr_pool_t *pool)
{
apr_array_header_t *ci = commit_items; /* convenience */
int i;
/* Sort our commit items by their URLs. */
svn_sort__array(ci, sort_commit_item_urls);
/* Hack BASE_URL off each URL; store the result as session_relpath. */
for (i = 0; i < ci->nelts; i++)
{
svn_client_commit_item3_t *this_item
= APR_ARRAY_IDX(ci, i, svn_client_commit_item3_t *);
this_item->session_relpath = svn_uri_skip_ancestor(base_url,
this_item->url, pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__condense_commit_items(const char **base_url,
@ -1501,8 +1524,6 @@ struct file_mod_t
/* A baton for use while driving a path-based editor driver for commit */
struct item_commit_baton
{
const svn_delta_editor_t *editor; /* commit editor */
void *edit_baton; /* commit editor's baton */
apr_hash_t *file_mods; /* hash: path->file_mod_t */
const char *notify_path_prefix; /* notification path prefix
(NULL is okay, else abs path) */
@ -1524,6 +1545,8 @@ struct item_commit_baton
* This implements svn_delta_path_driver_cb_func_t. */
static svn_error_t *
do_item_commit(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *path,
@ -1535,7 +1558,6 @@ do_item_commit(void **dir_baton,
svn_node_kind_t kind = item->kind;
void *file_baton = NULL;
apr_pool_t *file_pool = NULL;
const svn_delta_editor_t *editor = icb->editor;
apr_hash_t *file_mods = icb->file_mods;
svn_client_ctx_t *ctx = icb->ctx;
svn_error_t *err;
@ -1737,7 +1759,7 @@ do_item_commit(void **dir_baton,
{
if (! parent_baton)
{
err = editor->open_root(icb->edit_baton, item->revision,
err = editor->open_root(edit_baton, item->revision,
pool, dir_baton);
}
else
@ -1871,8 +1893,6 @@ svn_client__do_commit(const char *base_url,
}
/* Setup the callback baton. */
cb_baton.editor = editor;
cb_baton.edit_baton = edit_baton;
cb_baton.file_mods = file_mods;
cb_baton.notify_path_prefix = notify_path_prefix;
cb_baton.ctx = ctx;
@ -1880,7 +1900,7 @@ svn_client__do_commit(const char *base_url,
cb_baton.base_url = base_url;
/* Drive the commit editor! */
SVN_ERR(svn_delta_path_driver2(editor, edit_baton, paths, TRUE,
SVN_ERR(svn_delta_path_driver3(editor, edit_baton, paths, TRUE,
do_item_commit, &cb_baton, scratch_pool));
/* Transmit outstanding text deltas. */

File diff suppressed because it is too large Load Diff

View File

@ -578,7 +578,7 @@ pin_externals_prop(svn_string_t **pinned_externals,
static svn_error_t *
resolve_pinned_externals(apr_hash_t **pinned_externals,
const apr_hash_t *externals_to_pin,
svn_client__copy_pair_t *pair,
const svn_client__copy_pair_t *pair,
svn_ra_session_t *ra_session,
const char *repos_root_url,
svn_client_ctx_t *ctx,
@ -1099,14 +1099,13 @@ verify_wc_dsts(const apr_array_header_t *copy_pairs,
return SVN_NO_ERROR;
}
/* Verify that the WC sources in COPY_PAIRS exist, and set pair->src_kind
for each.
*/
static svn_error_t *
verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
svn_boolean_t make_parents,
svn_boolean_t is_move,
svn_boolean_t metadata_only,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
verify_wc_srcs(const apr_array_header_t *copy_pairs,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@ -1133,10 +1132,6 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
pair->src_abspath_or_url,
scratch_pool));
}
SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, metadata_only, ctx,
result_pool, iterpool));
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
@ -1163,10 +1158,6 @@ typedef struct path_driver_info_t
or move operation. */
struct path_driver_cb_baton
{
/* The editor (and its state) used to perform the operation. */
const svn_delta_editor_t *editor;
void *edit_baton;
/* A hash of path -> path_driver_info_t *'s. */
apr_hash_t *action_hash;
@ -1176,6 +1167,8 @@ struct path_driver_cb_baton
static svn_error_t *
path_driver_cb_func(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *path,
@ -1196,9 +1189,9 @@ path_driver_cb_func(void **dir_baton,
/* Check to see if we need to add the path as a parent directory. */
if (path_info->dir_add)
{
return cb_baton->editor->add_directory(path, parent_baton, NULL,
SVN_INVALID_REVNUM, pool,
dir_baton);
return editor->add_directory(path, parent_baton, NULL,
SVN_INVALID_REVNUM, pool,
dir_baton);
}
/* If this is a resurrection, we know the source and dest paths are
@ -1230,8 +1223,8 @@ path_driver_cb_func(void **dir_baton,
if (do_delete)
{
SVN_ERR(cb_baton->editor->delete_entry(path, SVN_INVALID_REVNUM,
parent_baton, pool));
SVN_ERR(editor->delete_entry(path, SVN_INVALID_REVNUM,
parent_baton, pool));
}
if (do_add)
{
@ -1240,40 +1233,40 @@ path_driver_cb_func(void **dir_baton,
if (path_info->src_kind == svn_node_file)
{
void *file_baton;
SVN_ERR(cb_baton->editor->add_file(path, parent_baton,
path_info->src_url,
path_info->src_revnum,
pool, &file_baton));
SVN_ERR(editor->add_file(path, parent_baton,
path_info->src_url,
path_info->src_revnum,
pool, &file_baton));
if (path_info->mergeinfo)
SVN_ERR(cb_baton->editor->change_file_prop(file_baton,
SVN_PROP_MERGEINFO,
path_info->mergeinfo,
pool));
SVN_ERR(cb_baton->editor->close_file(file_baton, NULL, pool));
SVN_ERR(editor->change_file_prop(file_baton,
SVN_PROP_MERGEINFO,
path_info->mergeinfo,
pool));
SVN_ERR(editor->close_file(file_baton, NULL, pool));
}
else
{
SVN_ERR(cb_baton->editor->add_directory(path, parent_baton,
path_info->src_url,
path_info->src_revnum,
pool, dir_baton));
SVN_ERR(editor->add_directory(path, parent_baton,
path_info->src_url,
path_info->src_revnum,
pool, dir_baton));
if (path_info->mergeinfo)
SVN_ERR(cb_baton->editor->change_dir_prop(*dir_baton,
SVN_PROP_MERGEINFO,
path_info->mergeinfo,
pool));
SVN_ERR(editor->change_dir_prop(*dir_baton,
SVN_PROP_MERGEINFO,
path_info->mergeinfo,
pool));
}
}
if (path_info->externals)
{
if (*dir_baton == NULL)
SVN_ERR(cb_baton->editor->open_directory(path, parent_baton,
SVN_INVALID_REVNUM,
pool, dir_baton));
SVN_ERR(editor->open_directory(path, parent_baton,
SVN_INVALID_REVNUM,
pool, dir_baton));
SVN_ERR(cb_baton->editor->change_dir_prop(*dir_baton, SVN_PROP_EXTERNALS,
path_info->externals, pool));
SVN_ERR(editor->change_dir_prop(*dir_baton, SVN_PROP_EXTERNALS,
path_info->externals, pool));
}
return SVN_NO_ERROR;
@ -1857,13 +1850,11 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
pool));
/* Setup the callback baton. */
cb_baton.editor = editor;
cb_baton.edit_baton = edit_baton;
cb_baton.action_hash = action_hash;
cb_baton.is_move = is_move;
/* Call the path-based editor driver. */
err = svn_delta_path_driver2(editor, edit_baton, paths, TRUE,
err = svn_delta_path_driver3(editor, edit_baton, paths, TRUE,
path_driver_cb_func, &cb_baton, pool);
if (err)
{
@ -2318,9 +2309,15 @@ struct notification_adjust_baton
};
/* A svn_wc_notify_func2_t function that wraps BATON->inner_func (whose
* baton is BATON->inner_baton) and adjusts the notification paths that
* start with BATON->checkout_abspath to start instead with
* BATON->final_abspath. */
* baton is BATON->inner_baton) to turn the result of a 'checkout' into
* what we want to see for a 'copy to WC' operation.
*
* - Adjust the notification paths that start with BATON->checkout_abspath
* to start instead with BATON->final_abspath.
* - Change start-of-update notification into a plain WC 'add' for the root.
* - Change checkout 'add' notifications into a plain WC 'add'.
* - Discard 'update_completed' notifications.
*/
static void
notification_adjust_func(void *baton,
const svn_wc_notify_t *notify,
@ -2333,18 +2330,372 @@ notification_adjust_func(void *baton,
relpath = svn_dirent_skip_ancestor(nb->checkout_abspath, notify->path);
inner_notify->path = svn_dirent_join(nb->final_abspath, relpath, pool);
/* Convert 'update' notifications to plain 'add' notifications; discard
notifications about checkout/update starting/finishing. */
if (notify->action == svn_wc_notify_update_started /* root */
|| notify->action == svn_wc_notify_update_add) /* non-root */
{
inner_notify->action = svn_wc_notify_add;
}
else if (notify->action == svn_wc_notify_update_update
|| notify->action == svn_wc_notify_update_completed)
{
/* update_update happens only for a prop mod on root; the root was
already notified so discard this */
return;
}
if (nb->inner_func)
nb->inner_func(nb->inner_baton, inner_notify, pool);
}
/** Copy a directory tree from a remote repository.
*
* Copy from RA_SESSION:LOCATION to WC_CTX:DST_ABSPATH.
*
* Create the directory DST_ABSPATH, if not present. Its parent should be
* already under version control in the WC and in a suitable state for
* scheduling the addition of a child.
*
* Ignore any incoming non-regular properties (entry-props, DAV/WC-props).
* Remove any incoming 'svn:mergeinfo' properties.
*/
static svn_error_t *
copy_foreign_dir(svn_ra_session_t *ra_session,
const svn_client__pathrev_t *location,
const char *dst_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *editor;
void *eb;
const svn_delta_editor_t *wrapped_editor;
void *wrapped_baton;
const svn_ra_reporter3_t *reporter;
void *reporter_baton;
/* Get a WC editor. It does not need an RA session because we will not
be sending it any 'copy from' requests, only 'add' requests. */
SVN_ERR(svn_client__wc_editor_internal(&editor, &eb,
dst_abspath,
TRUE /*root_dir_add*/,
TRUE /*ignore_mergeinfo_changes*/,
FALSE /*manage_wc_write_lock*/,
notify_func, notify_baton,
NULL /*ra_session*/,
ctx, scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
editor, eb,
&wrapped_editor, &wrapped_baton,
scratch_pool));
SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &reporter_baton,
location->rev, "", svn_depth_infinity,
FALSE, FALSE, wrapped_editor, wrapped_baton,
scratch_pool, scratch_pool));
SVN_ERR(reporter->set_path(reporter_baton, "", location->rev,
svn_depth_infinity /* irrelevant */,
TRUE /*start_empty*/,
NULL, scratch_pool));
SVN_ERR(reporter->finish_report(reporter_baton, scratch_pool));
return SVN_NO_ERROR;
}
/* Implementation of svn_client__repos_to_wc_copy() for a dir.
*/
static svn_error_t *
svn_client__repos_to_wc_copy_dir(svn_boolean_t *timestamp_sleep,
const char *src_url,
svn_revnum_t src_revnum,
const char *dst_abspath,
svn_boolean_t same_repositories,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const char *tmpdir_abspath, *tmp_abspath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
if (!same_repositories)
{
svn_client__pathrev_t *location;
*timestamp_sleep = TRUE;
/* ### Reparenting "ra_session" can't be right, can it? As this is
a foreign repo, surely we need a new RA session? */
SVN_ERR(svn_client__pathrev_create_with_session(&location, ra_session,
src_revnum, src_url,
scratch_pool));
SVN_ERR(svn_ra_reparent(ra_session, src_url, scratch_pool));
SVN_ERR(copy_foreign_dir(ra_session, location,
dst_abspath,
ctx->notify_func2, ctx->notify_baton2,
ctx->cancel_func, ctx->cancel_baton,
ctx, scratch_pool));
return SVN_NO_ERROR;
}
/* Find a temporary location in which to check out the copy source. */
SVN_ERR(svn_wc__get_tmpdir(&tmpdir_abspath, ctx->wc_ctx, dst_abspath,
scratch_pool, scratch_pool));
/* Get a temporary path. The crude way we do this is to create a
temporary file, remember its name, and let it be deleted immediately. */
SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_abspath, tmpdir_abspath,
svn_io_file_del_on_close,
scratch_pool, scratch_pool));
/* Make a new checkout of the requested source. While doing so,
* resolve copy_src_revnum to an actual revision number in case it
* was until now 'invalid' meaning 'head'. Ask this function not to
* sleep for timestamps, by passing a sleep_needed output param.
* Send notifications for all nodes except the root node, and adjust
* them to refer to the destination rather than this temporary path. */
{
svn_wc_notify_func2_t old_notify_func2 = ctx->notify_func2;
void *old_notify_baton2 = ctx->notify_baton2;
struct notification_adjust_baton nb;
svn_error_t *err;
svn_opt_revision_t copy_src_revision;
copy_src_revision.kind = svn_opt_revision_number;
copy_src_revision.value.number = src_revnum;
nb.inner_func = ctx->notify_func2;
nb.inner_baton = ctx->notify_baton2;
nb.checkout_abspath = tmp_abspath;
nb.final_abspath = dst_abspath;
ctx->notify_func2 = notification_adjust_func;
ctx->notify_baton2 = &nb;
err = svn_client__checkout_internal(NULL /*result_rev*/, timestamp_sleep,
src_url,
tmp_abspath,
&copy_src_revision,
&copy_src_revision,
svn_depth_infinity,
TRUE /*ignore_externals*/,
FALSE, /* we don't allow obstructions */
ra_session, ctx, scratch_pool);
ctx->notify_func2 = old_notify_func2;
ctx->notify_baton2 = old_notify_baton2;
SVN_ERR(err);
}
/* Schedule dst_path for addition in parent, with copy history.
Don't send any notification here.
Then remove the temporary checkout's .svn dir in preparation for
moving the rest of it into the final destination. */
SVN_ERR(svn_wc_copy3(ctx->wc_ctx, tmp_abspath, dst_abspath,
TRUE /* metadata_only */,
NULL, NULL, /* don't allow user to cancel here */
NULL, NULL, scratch_pool));
SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, tmp_abspath,
FALSE, scratch_pool, scratch_pool));
SVN_ERR(svn_wc_remove_from_revision_control2(ctx->wc_ctx,
tmp_abspath,
FALSE, FALSE,
NULL, NULL, /* don't cancel */
scratch_pool));
/* Move the temporary disk tree into place. */
SVN_ERR(svn_io_file_rename2(tmp_abspath, dst_abspath, FALSE, scratch_pool));
return SVN_NO_ERROR;
}
/* Implementation of svn_client__repos_to_wc_copy() for a file.
*
* This has no 'ignore_externals' parameter because we don't support the
* 'svn:externals' property being set on a file.
*/
static svn_error_t *
svn_client__repos_to_wc_copy_file(svn_boolean_t *timestamp_sleep,
const char *src_url,
svn_revnum_t src_rev,
const char *dst_abspath,
svn_boolean_t same_repositories,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const char *src_rel;
apr_hash_t *new_props;
svn_stream_t *new_base_contents = svn_stream_buffered(scratch_pool);
SVN_ERR(svn_ra_get_path_relative_to_session(ra_session, &src_rel, src_url,
scratch_pool));
/* Fetch the file content. */
SVN_ERR(svn_ra_get_file(ra_session, src_rel, src_rev,
new_base_contents, NULL, &new_props,
scratch_pool));
if (!same_repositories)
svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
*timestamp_sleep = TRUE;
SVN_ERR(svn_wc_add_repos_file4(
ctx->wc_ctx, dst_abspath,
new_base_contents, NULL, new_props, NULL,
same_repositories ? src_url : NULL,
same_repositories ? src_rev : SVN_INVALID_REVNUM,
ctx->cancel_func, ctx->cancel_baton,
scratch_pool));
/* Do our own notification for the root node, even if we could possibly
have delegated it. See also issue #2198. */
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
= svn_wc_create_notify(dst_abspath, svn_wc_notify_add, scratch_pool);
notify->kind = svn_node_file;
ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
}
return SVN_NO_ERROR;
}
/* Are RA_SESSION and the versioned *parent* dir of WC_TARGET_ABSPATH in
* the same repository?
*/
static svn_error_t *
is_same_repository(svn_boolean_t *same_repository,
svn_ra_session_t *ra_session,
const char *wc_target_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const char *src_uuid, *dst_uuid;
/* Get the repository UUIDs of copy source URL and WC parent path */
SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool));
SVN_ERR(svn_client_get_repos_root(NULL /*root_url*/, &dst_uuid,
svn_dirent_dirname(wc_target_abspath,
scratch_pool),
ctx, scratch_pool, scratch_pool));
*same_repository = (strcmp(src_uuid, dst_uuid) == 0);
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__repos_to_wc_copy_internal(svn_boolean_t *timestamp_sleep,
svn_node_kind_t kind,
const char *src_url,
svn_revnum_t src_rev,
const char *dst_abspath,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const char *old_session_url;
svn_boolean_t timestamp_sleep_ignored;
svn_boolean_t same_repositories;
SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
src_url, scratch_pool));
SVN_ERR(is_same_repository(&same_repositories,
ra_session, dst_abspath, ctx, scratch_pool));
if (!timestamp_sleep)
timestamp_sleep = &timestamp_sleep_ignored;
if (kind == svn_node_dir)
{
SVN_ERR(svn_client__repos_to_wc_copy_dir(timestamp_sleep,
src_url, src_rev,
dst_abspath,
same_repositories,
ra_session,
ctx, scratch_pool));
}
else if (kind == svn_node_file)
{
SVN_ERR(svn_client__repos_to_wc_copy_file(timestamp_sleep,
src_url, src_rev,
dst_abspath,
same_repositories,
ra_session,
ctx, scratch_pool));
}
/* Reparent the session back to the original URL. */
SVN_ERR(svn_ra_reparent(ra_session, old_session_url, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__repos_to_wc_copy_by_editor(svn_boolean_t *timestamp_sleep,
svn_node_kind_t kind,
const char *src_url,
svn_revnum_t src_rev,
const char *dst_abspath,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *editor;
void *eb;
const char *src_anchor = svn_uri_dirname(src_url, scratch_pool);
const char *dst_target = svn_dirent_basename(dst_abspath, scratch_pool);
void *rb, *db;
SVN_ERR(svn_ra_reparent(ra_session, src_anchor, scratch_pool));
SVN_ERR(svn_client__wc_editor_internal(
&editor, &eb,
svn_dirent_dirname(dst_abspath, scratch_pool),
FALSE /*root_dir_add*/,
FALSE /*ignore_mergeinfo_changes*/,
FALSE /*manage_wc_write_lock*/,
ctx->notify_func2, ctx->notify_baton2,
ra_session,
ctx, scratch_pool));
SVN_ERR(editor->open_root(eb, SVN_INVALID_REVNUM, scratch_pool, &rb));
if (kind == svn_node_dir)
{
SVN_ERR(editor->add_directory(dst_target, rb,
src_url, src_rev,
scratch_pool,
&db));
SVN_ERR(editor->close_directory(db, scratch_pool));
}
else
{
SVN_ERR(editor->add_file(dst_target, rb,
src_url, src_rev,
scratch_pool,
&db));
SVN_ERR(editor->close_file(db, NULL, scratch_pool));
}
SVN_ERR(editor->close_edit(eb, scratch_pool));
if (timestamp_sleep)
*timestamp_sleep = TRUE;
return SVN_NO_ERROR;
}
/* Peform each individual copy operation for a repos -> wc copy. A
helper for repos_to_wc_copy().
Resolve PAIR->src_revnum to a real revision number if it isn't already. */
PAIR->src_revnum PAIR->src_abspath_or_url should already have been
resolved to the operative revision number and operative URL.
*/
static svn_error_t *
repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
svn_client__copy_pair_t *pair,
svn_boolean_t same_repositories,
const svn_client__copy_pair_t *pair,
svn_boolean_t ignore_externals,
svn_boolean_t pin_externals,
const apr_hash_t *externals_to_pin,
@ -2354,9 +2705,14 @@ repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
{
apr_hash_t *src_mergeinfo;
const char *dst_abspath = pair->dst_abspath_or_url;
svn_boolean_t same_repositories;
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(pair->src_revnum));
SVN_ERR_ASSERT(svn_path_is_url(pair->src_abspath_or_url));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
SVN_ERR(is_same_repository(&same_repositories,
ra_session, dst_abspath, ctx, pool));
if (!same_repositories && ctx->notify_func2)
{
svn_wc_notify_t *notify;
@ -2372,135 +2728,59 @@ repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
}
if (pair->src_kind == svn_node_dir)
SVN_ERR(svn_client__repos_to_wc_copy_by_editor(
timestamp_sleep,
pair->src_kind,
pair->src_abspath_or_url,
pair->src_revnum,
dst_abspath,
ra_session, ctx, pool));
/* Fetch externals, pinning them if requested */
if (!ignore_externals && pair->src_kind == svn_node_dir)
{
if (same_repositories)
{
const char *tmpdir_abspath, *tmp_abspath;
/* Find a temporary location in which to check out the copy source. */
SVN_ERR(svn_wc__get_tmpdir(&tmpdir_abspath, ctx->wc_ctx, dst_abspath,
pool, pool));
SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_abspath, tmpdir_abspath,
svn_io_file_del_on_close, pool, pool));
/* Make a new checkout of the requested source. While doing so,
* resolve pair->src_revnum to an actual revision number in case it
* was until now 'invalid' meaning 'head'. Ask this function not to
* sleep for timestamps, by passing a sleep_needed output param.
* Send notifications for all nodes except the root node, and adjust
* them to refer to the destination rather than this temporary path. */
{
svn_wc_notify_func2_t old_notify_func2 = ctx->notify_func2;
void *old_notify_baton2 = ctx->notify_baton2;
struct notification_adjust_baton nb;
svn_error_t *err;
nb.inner_func = ctx->notify_func2;
nb.inner_baton = ctx->notify_baton2;
nb.checkout_abspath = tmp_abspath;
nb.final_abspath = dst_abspath;
ctx->notify_func2 = notification_adjust_func;
ctx->notify_baton2 = &nb;
/* Avoid a chicken-and-egg problem:
* If pinning externals we'll need to adjust externals
* properties before checking out any externals.
* But copy needs to happen before pinning because else there
* are no svn:externals properties to pin. */
if (pin_externals)
ignore_externals = TRUE;
err = svn_client__checkout_internal(&pair->src_revnum, timestamp_sleep,
pair->src_original,
tmp_abspath,
&pair->src_peg_revision,
&pair->src_op_revision,
svn_depth_infinity,
ignore_externals, FALSE,
ra_session, ctx, pool);
ctx->notify_func2 = old_notify_func2;
ctx->notify_baton2 = old_notify_baton2;
SVN_ERR(err);
}
*timestamp_sleep = TRUE;
/* Schedule dst_path for addition in parent, with copy history.
Don't send any notification here.
Then remove the temporary checkout's .svn dir in preparation for
moving the rest of it into the final destination. */
SVN_ERR(svn_wc_copy3(ctx->wc_ctx, tmp_abspath, dst_abspath,
TRUE /* metadata_only */,
ctx->cancel_func, ctx->cancel_baton,
NULL, NULL, pool));
SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, tmp_abspath,
FALSE, pool, pool));
SVN_ERR(svn_wc_remove_from_revision_control2(ctx->wc_ctx,
tmp_abspath,
FALSE, FALSE,
ctx->cancel_func,
ctx->cancel_baton,
pool));
/* Move the temporary disk tree into place. */
SVN_ERR(svn_io_file_rename2(tmp_abspath, dst_abspath, FALSE, pool));
}
else
{
*timestamp_sleep = TRUE;
SVN_ERR(svn_client__copy_foreign(pair->src_abspath_or_url,
dst_abspath,
&pair->src_peg_revision,
&pair->src_op_revision,
svn_depth_infinity,
FALSE /* make_parents */,
TRUE /* already_locked */,
ctx, pool));
return SVN_NO_ERROR;
}
if (pin_externals)
{
apr_hash_t *pinned_externals;
apr_hash_index_t *hi;
apr_pool_t *iterpool;
const char *repos_root_url;
apr_hash_t *new_externals;
apr_hash_t *new_depths;
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
SVN_ERR(resolve_pinned_externals(&pinned_externals,
externals_to_pin, pair,
ra_session, repos_root_url,
ctx, pool, pool));
iterpool = svn_pool_create(pool);
for (hi = apr_hash_first(pool, pinned_externals);
hi;
hi = apr_hash_next(hi))
if (pin_externals)
{
const char *dst_relpath = apr_hash_this_key(hi);
svn_string_t *externals_propval = apr_hash_this_val(hi);
const char *local_abspath;
apr_hash_t *pinned_externals;
apr_hash_index_t *hi;
apr_pool_t *iterpool;
svn_pool_clear(iterpool);
SVN_ERR(resolve_pinned_externals(&pinned_externals,
externals_to_pin, pair,
ra_session, repos_root_url,
ctx, pool, pool));
local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
dst_relpath, iterpool);
/* ### use a work queue? */
SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
SVN_PROP_EXTERNALS, externals_propval,
svn_depth_empty, TRUE /* skip_checks */,
NULL /* changelist_filter */,
ctx->cancel_func, ctx->cancel_baton,
NULL, NULL, /* no extra notification */
iterpool));
iterpool = svn_pool_create(pool);
for (hi = apr_hash_first(pool, pinned_externals);
hi;
hi = apr_hash_next(hi))
{
const char *dst_relpath = apr_hash_this_key(hi);
svn_string_t *externals_propval = apr_hash_this_val(hi);
const char *local_abspath;
svn_pool_clear(iterpool);
local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
dst_relpath, iterpool);
/* ### use a work queue? */
SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
SVN_PROP_EXTERNALS, externals_propval,
svn_depth_empty, TRUE /* skip_checks */,
NULL /* changelist_filter */,
ctx->cancel_func, ctx->cancel_baton,
NULL, NULL, /* no extra notification */
iterpool));
}
svn_pool_destroy(iterpool);
}
/* Now update all externals in the newly created copy. */
@ -2509,65 +2789,30 @@ repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
ctx->wc_ctx,
dst_abspath,
svn_depth_infinity,
iterpool, iterpool));
pool, pool));
SVN_ERR(svn_client__handle_externals(new_externals,
new_depths,
repos_root_url, dst_abspath,
svn_depth_infinity,
timestamp_sleep,
ra_session,
ctx, iterpool));
svn_pool_destroy(iterpool);
ctx, pool));
}
} /* end directory case */
else if (pair->src_kind == svn_node_file)
{
apr_hash_t *new_props;
const char *src_rel;
svn_stream_t *new_base_contents = svn_stream_buffered(pool);
SVN_ERR(svn_ra_get_path_relative_to_session(ra_session, &src_rel,
pair->src_abspath_or_url,
pool));
/* Fetch the file content. While doing so, resolve pair->src_revnum
* to an actual revision number if it's 'invalid' meaning 'head'. */
SVN_ERR(svn_ra_get_file(ra_session, src_rel, pair->src_revnum,
new_base_contents,
&pair->src_revnum, &new_props, pool));
if (new_props && ! same_repositories)
svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
*timestamp_sleep = TRUE;
SVN_ERR(svn_wc_add_repos_file4(
ctx->wc_ctx, dst_abspath,
new_base_contents, NULL, new_props, NULL,
same_repositories ? pair->src_abspath_or_url : NULL,
same_repositories ? pair->src_revnum : SVN_INVALID_REVNUM,
ctx->cancel_func, ctx->cancel_baton,
pool));
}
/* Record the implied mergeinfo (before the notification callback
is invoked for the root node). */
SVN_ERR(svn_client__get_repos_mergeinfo(
&src_mergeinfo, ra_session,
pair->src_abspath_or_url, pair->src_revnum,
svn_mergeinfo_inherited, TRUE /*squelch_incapable*/, pool));
SVN_ERR(extend_wc_mergeinfo(dst_abspath, src_mergeinfo, ctx, pool));
/* Do our own notification for the root node, even if we could possibly
have delegated it. See also issue #1552.
### Maybe this notification should mention the mergeinfo change. */
if (ctx->notify_func2)
if (same_repositories)
{
svn_wc_notify_t *notify = svn_wc_create_notify(
dst_abspath, svn_wc_notify_add, pool);
notify->kind = pair->src_kind;
ctx->notify_func2(ctx->notify_baton2, notify, pool);
/* Record the implied mergeinfo. */
SVN_ERR(svn_client__get_repos_mergeinfo(&src_mergeinfo, ra_session,
pair->src_abspath_or_url,
pair->src_revnum,
svn_mergeinfo_inherited,
TRUE /*squelch_incapable*/,
pool));
SVN_ERR(extend_wc_mergeinfo(dst_abspath, src_mergeinfo, ctx, pool));
/* ### Maybe the notification should mention this mergeinfo change. */
/* ### Maybe we should do this during rather than after the copy. */
}
return SVN_NO_ERROR;
@ -2585,38 +2830,8 @@ repos_to_wc_copy_locked(svn_boolean_t *timestamp_sleep,
apr_pool_t *scratch_pool)
{
int i;
svn_boolean_t same_repositories;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
/* We've already checked for physical obstruction by a working file.
But there could also be logical obstruction by an entry whose
working file happens to be missing.*/
SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, FALSE /* metadata_only */,
ctx, scratch_pool, iterpool));
/* Decide whether the two repositories are the same or not. */
{
const char *parent_abspath;
const char *src_uuid, *dst_uuid;
/* Get the repository uuid of SRC_URL */
SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, iterpool));
/* Get repository uuid of dst's parent directory, since dst may
not exist. ### TODO: we should probably walk up the wc here,
in case the parent dir has an imaginary URL. */
if (copy_pairs->nelts == 1)
parent_abspath = svn_dirent_dirname(top_dst_abspath, scratch_pool);
else
parent_abspath = top_dst_abspath;
SVN_ERR(svn_client_get_repos_root(NULL /* root_url */, &dst_uuid,
parent_abspath, ctx,
iterpool, iterpool));
/* ### Also check repos_root_url? */
same_repositories = (strcmp(src_uuid, dst_uuid) == 0);
}
/* Perform the move for each of the copy_pairs. */
for (i = 0; i < copy_pairs->nelts; i++)
{
@ -2629,7 +2844,6 @@ repos_to_wc_copy_locked(svn_boolean_t *timestamp_sleep,
SVN_ERR(repos_to_wc_copy_single(timestamp_sleep,
APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *),
same_repositories,
ignore_externals,
pin_externals, externals_to_pin,
ra_session, ctx, iterpool));
@ -2642,7 +2856,6 @@ repos_to_wc_copy_locked(svn_boolean_t *timestamp_sleep,
static svn_error_t *
repos_to_wc_copy(svn_boolean_t *timestamp_sleep,
const apr_array_header_t *copy_pairs,
svn_boolean_t make_parents,
svn_boolean_t ignore_externals,
svn_boolean_t pin_externals,
const apr_hash_t *externals_to_pin,
@ -2696,8 +2909,6 @@ repos_to_wc_copy(svn_boolean_t *timestamp_sleep,
{
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
svn_node_kind_t dst_parent_kind, dst_kind;
const char *dst_parent;
const char *src_rel;
svn_pool_clear(iterpool);
@ -2721,33 +2932,6 @@ repos_to_wc_copy(svn_boolean_t *timestamp_sleep,
_("Path '%s' not found in head revision"),
pair->src_abspath_or_url);
}
/* Figure out about dst. */
SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind,
iterpool));
if (dst_kind != svn_node_none)
{
return svn_error_createf(
SVN_ERR_ENTRY_EXISTS, NULL,
_("Path '%s' already exists"),
svn_dirent_local_style(pair->dst_abspath_or_url, pool));
}
/* Make sure the destination parent is a directory and produce a clear
error message if it is not. */
dst_parent = svn_dirent_dirname(pair->dst_abspath_or_url, iterpool);
SVN_ERR(svn_io_check_path(dst_parent, &dst_parent_kind, iterpool));
if (make_parents && dst_parent_kind == svn_node_none)
{
SVN_ERR(svn_client__make_local_parents(dst_parent, TRUE, ctx,
iterpool));
}
else if (dst_parent_kind != svn_node_dir)
{
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
_("Path '%s' is not a directory"),
svn_dirent_local_style(dst_parent, pool));
}
}
svn_pool_destroy(iterpool);
@ -3070,8 +3254,9 @@ try_copy(svn_boolean_t *timestamp_sleep,
/* Now, call the right handler for the operation. */
if ((! srcs_are_urls) && (! dst_is_url))
{
SVN_ERR(verify_wc_srcs_and_dsts(copy_pairs, make_parents, is_move,
metadata_only, ctx, pool, pool));
SVN_ERR(verify_wc_srcs(copy_pairs, ctx, pool));
SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, metadata_only,
ctx, pool, pool));
/* Copy or move all targets. */
if (is_move)
@ -3101,9 +3286,13 @@ try_copy(svn_boolean_t *timestamp_sleep,
}
else if ((srcs_are_urls) && (! dst_is_url))
{
SVN_ERR(verify_wc_dsts(copy_pairs, make_parents,
FALSE, FALSE /* metadata_only */,
ctx, pool, pool));
return svn_error_trace(
repos_to_wc_copy(timestamp_sleep,
copy_pairs, make_parents, ignore_externals,
copy_pairs, ignore_externals,
pin_externals, externals_to_pin, ctx, pool));
}
else

View File

@ -1,575 +0,0 @@
/*
* copy_foreign.c: copy from other repository support.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include <string.h>
#include "svn_hash.h"
#include "svn_client.h"
#include "svn_delta.h"
#include "svn_dirent_uri.h"
#include "svn_error.h"
#include "svn_error_codes.h"
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_props.h"
#include "svn_ra.h"
#include "svn_wc.h"
#include <apr_md5.h>
#include "client.h"
#include "private/svn_subr_private.h"
#include "private/svn_wc_private.h"
#include "svn_private_config.h"
struct edit_baton_t
{
apr_pool_t *pool;
const char *anchor_abspath;
svn_wc_context_t *wc_ctx;
svn_wc_notify_func2_t notify_func;
void *notify_baton;
};
struct dir_baton_t
{
apr_pool_t *pool;
struct dir_baton_t *pb;
struct edit_baton_t *eb;
const char *local_abspath;
svn_boolean_t created;
apr_hash_t *properties;
int users;
};
/* svn_delta_editor_t function */
static svn_error_t *
edit_open(void *edit_baton,
svn_revnum_t base_revision,
apr_pool_t *result_pool,
void **root_baton)
{
struct edit_baton_t *eb = edit_baton;
apr_pool_t *dir_pool = svn_pool_create(eb->pool);
struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db));
db->pool = dir_pool;
db->eb = eb;
db->users = 1;
db->local_abspath = eb->anchor_abspath;
SVN_ERR(svn_io_make_dir_recursively(eb->anchor_abspath, dir_pool));
*root_baton = db;
return SVN_NO_ERROR;
}
/* svn_delta_editor_t function */
static svn_error_t *
edit_close(void *edit_baton,
apr_pool_t *scratch_pool)
{
return SVN_NO_ERROR;
}
static svn_error_t *
dir_add(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *result_pool,
void **child_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
apr_pool_t *dir_pool = svn_pool_create(pb->pool);
struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db));
svn_boolean_t under_root;
pb->users++;
db->pb = pb;
db->eb = pb->eb;
db->pool = dir_pool;
db->users = 1;
SVN_ERR(svn_dirent_is_under_root(&under_root, &db->local_abspath,
eb->anchor_abspath, path, db->pool));
if (! under_root)
{
return svn_error_createf(
SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("Path '%s' is not in the working copy"),
svn_dirent_local_style(path, db->pool));
}
SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool));
*child_baton = db;
return SVN_NO_ERROR;
}
static svn_error_t *
dir_change_prop(void *dir_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *scratch_pool)
{
struct dir_baton_t *db = dir_baton;
struct edit_baton_t *eb = db->eb;
svn_prop_kind_t prop_kind;
prop_kind = svn_property_kind2(name);
if (prop_kind != svn_prop_regular_kind
|| ! strcmp(name, SVN_PROP_MERGEINFO))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
}
if (! db->created)
{
/* We can still store them in the hash for immediate addition
with the svn_wc_add_from_disk3() call */
if (! db->properties)
db->properties = apr_hash_make(db->pool);
if (value != NULL)
svn_hash_sets(db->properties, apr_pstrdup(db->pool, name),
svn_string_dup(value, db->pool));
}
else
{
/* We have already notified for this directory, so don't do that again */
SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value,
svn_depth_empty, FALSE, NULL,
NULL, NULL, /* Cancellation */
NULL, NULL, /* Notification */
scratch_pool));
}
return SVN_NO_ERROR;
}
/* Releases the directory baton if there are no more users */
static svn_error_t *
maybe_done(struct dir_baton_t *db)
{
db->users--;
if (db->users == 0)
{
struct dir_baton_t *pb = db->pb;
svn_pool_clear(db->pool);
if (pb)
SVN_ERR(maybe_done(pb));
}
return SVN_NO_ERROR;
}
static svn_error_t *
ensure_added(struct dir_baton_t *db,
apr_pool_t *scratch_pool)
{
if (db->created)
return SVN_NO_ERROR;
if (db->pb)
SVN_ERR(ensure_added(db->pb, scratch_pool));
db->created = TRUE;
/* Add the directory with all the already collected properties */
SVN_ERR(svn_wc_add_from_disk3(db->eb->wc_ctx,
db->local_abspath,
db->properties,
TRUE /* skip checks */,
db->eb->notify_func,
db->eb->notify_baton,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
dir_close(void *dir_baton,
apr_pool_t *scratch_pool)
{
struct dir_baton_t *db = dir_baton;
/*struct edit_baton_t *eb = db->eb;*/
SVN_ERR(ensure_added(db, scratch_pool));
SVN_ERR(maybe_done(db));
return SVN_NO_ERROR;
}
struct file_baton_t
{
apr_pool_t *pool;
struct dir_baton_t *pb;
struct edit_baton_t *eb;
const char *local_abspath;
apr_hash_t *properties;
svn_boolean_t writing;
unsigned char digest[APR_MD5_DIGESTSIZE];
const char *tmp_path;
};
static svn_error_t *
file_add(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *result_pool,
void **file_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
apr_pool_t *file_pool = svn_pool_create(pb->pool);
struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb));
svn_boolean_t under_root;
pb->users++;
fb->pool = file_pool;
fb->eb = eb;
fb->pb = pb;
SVN_ERR(svn_dirent_is_under_root(&under_root, &fb->local_abspath,
eb->anchor_abspath, path, fb->pool));
if (! under_root)
{
return svn_error_createf(
SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("Path '%s' is not in the working copy"),
svn_dirent_local_style(path, fb->pool));
}
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
file_change_prop(void *file_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
svn_prop_kind_t prop_kind;
prop_kind = svn_property_kind2(name);
if (prop_kind != svn_prop_regular_kind
|| ! strcmp(name, SVN_PROP_MERGEINFO))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
}
/* We store all properties in the hash for immediate addition
with the svn_wc_add_from_disk3() call */
if (! fb->properties)
fb->properties = apr_hash_make(fb->pool);
if (value != NULL)
svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
svn_string_dup(value, fb->pool));
return SVN_NO_ERROR;
}
static svn_error_t *
file_textdelta(void *file_baton,
const char *base_checksum,
apr_pool_t *result_pool,
svn_txdelta_window_handler_t *handler,
void **handler_baton)
{
struct file_baton_t *fb = file_baton;
svn_stream_t *target;
SVN_ERR_ASSERT(! fb->writing);
SVN_ERR(svn_stream_open_writable(&target, fb->local_abspath, fb->pool,
fb->pool));
fb->writing = TRUE;
svn_txdelta_apply(svn_stream_empty(fb->pool) /* source */,
target,
fb->digest,
fb->local_abspath,
fb->pool,
/* Provide the handler directly */
handler, handler_baton);
return SVN_NO_ERROR;
}
static svn_error_t *
file_close(void *file_baton,
const char *text_checksum,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
struct edit_baton_t *eb = fb->eb;
struct dir_baton_t *pb = fb->pb;
SVN_ERR(ensure_added(pb, fb->pool));
if (text_checksum)
{
svn_checksum_t *expected_checksum;
svn_checksum_t *actual_checksum;
SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5,
text_checksum, fb->pool));
actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool);
if (! svn_checksum_match(expected_checksum, actual_checksum))
return svn_error_trace(
svn_checksum_mismatch_err(expected_checksum,
actual_checksum,
fb->pool,
_("Checksum mismatch for '%s'"),
svn_dirent_local_style(
fb->local_abspath,
fb->pool)));
}
SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties,
TRUE /* skip checks */,
eb->notify_func, eb->notify_baton,
fb->pool));
svn_pool_destroy(fb->pool);
SVN_ERR(maybe_done(pb));
return SVN_NO_ERROR;
}
static svn_error_t *
copy_foreign_dir(svn_ra_session_t *ra_session,
svn_client__pathrev_t *location,
svn_wc_context_t *wc_ctx,
const char *dst_abspath,
svn_depth_t depth,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
struct edit_baton_t eb;
svn_delta_editor_t *editor = svn_delta_default_editor(scratch_pool);
const svn_delta_editor_t *wrapped_editor;
void *wrapped_baton;
const svn_ra_reporter3_t *reporter;
void *reporter_baton;
eb.pool = scratch_pool;
eb.anchor_abspath = dst_abspath;
eb.wc_ctx = wc_ctx;
eb.notify_func = notify_func;
eb.notify_baton = notify_baton;
editor->open_root = edit_open;
editor->close_edit = edit_close;
editor->add_directory = dir_add;
editor->change_dir_prop = dir_change_prop;
editor->close_directory = dir_close;
editor->add_file = file_add;
editor->change_file_prop = file_change_prop;
editor->apply_textdelta = file_textdelta;
editor->close_file = file_close;
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
editor, &eb,
&wrapped_editor, &wrapped_baton,
scratch_pool));
SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &reporter_baton,
location->rev, "", svn_depth_infinity,
FALSE, FALSE, wrapped_editor, wrapped_baton,
scratch_pool, scratch_pool));
SVN_ERR(reporter->set_path(reporter_baton, "", location->rev, depth,
TRUE /* incomplete */,
NULL, scratch_pool));
SVN_ERR(reporter->finish_report(reporter_baton, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__copy_foreign(const char *url,
const char *dst_abspath,
svn_opt_revision_t *peg_revision,
svn_opt_revision_t *revision,
svn_depth_t depth,
svn_boolean_t make_parents,
svn_boolean_t already_locked,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
svn_ra_session_t *ra_session;
svn_client__pathrev_t *loc;
svn_node_kind_t kind;
svn_node_kind_t wc_kind;
const char *dir_abspath;
SVN_ERR_ASSERT(svn_path_is_url(url));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
/* Do we need to validate/update revisions? */
SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
url, NULL,
peg_revision,
revision, ctx,
scratch_pool));
SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool));
if (kind != svn_node_file && kind != svn_node_dir)
return svn_error_createf(
SVN_ERR_ILLEGAL_TARGET, NULL,
_("'%s' is not a valid location inside a repository"),
url);
SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dst_abspath, FALSE, TRUE,
scratch_pool));
if (wc_kind != svn_node_none)
{
return svn_error_createf(
SVN_ERR_ENTRY_EXISTS, NULL,
_("'%s' is already under version control"),
svn_dirent_local_style(dst_abspath, scratch_pool));
}
dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
FALSE, FALSE, scratch_pool));
if (wc_kind == svn_node_none)
{
if (make_parents)
SVN_ERR(svn_client__make_local_parents(dir_abspath, make_parents, ctx,
scratch_pool));
SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
FALSE, FALSE, scratch_pool));
}
if (wc_kind != svn_node_dir)
return svn_error_createf(
SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("Can't add '%s', because no parent directory is found"),
svn_dirent_local_style(dst_abspath, scratch_pool));
if (kind == svn_node_file)
{
svn_stream_t *target;
apr_hash_t *props;
apr_hash_index_t *hi;
SVN_ERR(svn_stream_open_writable(&target, dst_abspath, scratch_pool,
scratch_pool));
SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, target, NULL, &props,
scratch_pool));
if (props != NULL)
for (hi = apr_hash_first(scratch_pool, props); hi;
hi = apr_hash_next(hi))
{
const char *name = apr_hash_this_key(hi);
if (svn_property_kind2(name) != svn_prop_regular_kind
|| ! strcmp(name, SVN_PROP_MERGEINFO))
{
/* We can't handle DAV, ENTRY and merge specific props here */
svn_hash_sets(props, name, NULL);
}
}
if (!already_locked)
SVN_WC__CALL_WITH_WRITE_LOCK(
svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props,
TRUE /* skip checks */,
ctx->notify_func2, ctx->notify_baton2,
scratch_pool),
ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
else
SVN_ERR(svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props,
TRUE /* skip checks */,
ctx->notify_func2, ctx->notify_baton2,
scratch_pool));
}
else
{
if (!already_locked)
SVN_WC__CALL_WITH_WRITE_LOCK(
copy_foreign_dir(ra_session, loc,
ctx->wc_ctx, dst_abspath,
depth,
ctx->notify_func2, ctx->notify_baton2,
ctx->cancel_func, ctx->cancel_baton,
scratch_pool),
ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
else
SVN_ERR(copy_foreign_dir(ra_session, loc,
ctx->wc_ctx, dst_abspath,
depth,
ctx->notify_func2, ctx->notify_baton2,
ctx->cancel_func, ctx->cancel_baton,
scratch_pool));
}
return SVN_NO_ERROR;
}

View File

@ -181,12 +181,13 @@ can_delete_node(svn_boolean_t *target_missing,
static svn_error_t *
path_driver_cb_func(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *path,
apr_pool_t *pool)
{
const svn_delta_editor_t *editor = callback_baton;
*dir_baton = NULL;
return editor->delete_entry(path, SVN_INVALID_REVNUM, parent_baton, pool);
}
@ -248,8 +249,8 @@ single_repos_delete(svn_ra_session_t *ra_session,
pool));
/* Call the path-based editor driver. */
err = svn_delta_path_driver2(editor, edit_baton, relpaths, TRUE,
path_driver_cb_func, (void *)editor, pool);
err = svn_delta_path_driver3(editor, edit_baton, relpaths, TRUE,
path_driver_cb_func, NULL, pool);
if (err)
{

View File

@ -166,6 +166,61 @@ svn_client_mkdir(svn_client_commit_info_t **commit_info_p,
}
/*** From blame.c ***/
struct blame_receiver_wrapper_baton3 {
void *baton;
svn_client_blame_receiver3_t receiver;
svn_revnum_t start_revnum;
svn_revnum_t end_revnum;
};
static svn_error_t *
blame_wrapper_receiver3(void *baton,
apr_int64_t line_no,
svn_revnum_t revision,
apr_hash_t *rev_props,
svn_revnum_t merged_revision,
apr_hash_t *merged_rev_props,
const char *merged_path,
const svn_string_t *line,
svn_boolean_t local_change,
apr_pool_t *pool)
{
struct blame_receiver_wrapper_baton3 *brwb = baton;
if (brwb->receiver)
return brwb->receiver(brwb->baton, brwb->start_revnum, brwb->end_revnum,
line_no,
revision, rev_props, merged_revision,
merged_rev_props, merged_path, line->data,
local_change, pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_blame5(const char *target,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *start,
const svn_opt_revision_t *end,
const svn_diff_file_options_t *diff_options,
svn_boolean_t ignore_mime_type,
svn_boolean_t include_merged_revisions,
svn_client_blame_receiver3_t receiver,
void *receiver_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
struct blame_receiver_wrapper_baton3 baton;
baton.receiver = receiver;
baton.baton = receiver_baton;
return svn_client_blame6(&baton.start_revnum, &baton.end_revnum,
target, peg_revision, start, end,
diff_options,
ignore_mime_type, include_merged_revisions,
blame_wrapper_receiver3, &baton, ctx, pool);
}
struct blame_receiver_wrapper_baton2 {
void *baton;
@ -935,6 +990,42 @@ svn_client_delete(svn_client_commit_info_t **commit_info_p,
/*** From diff.c ***/
svn_error_t *
svn_client_diff6(const apr_array_header_t *diff_options,
const char *path_or_url1,
const svn_opt_revision_t *revision1,
const char *path_or_url2,
const svn_opt_revision_t *revision2,
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t no_diff_added,
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
svn_boolean_t ignore_properties,
svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
const char *header_encoding,
svn_stream_t *outstream,
svn_stream_t *errstream,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
return svn_client_diff7(diff_options,
path_or_url1, revision1,
path_or_url2, revision2,
relative_to_dir, depth,
ignore_ancestry, no_diff_added,
no_diff_deleted, show_copies_as_adds,
ignore_content_type, ignore_properties,
properties_only, use_git_diff_format,
TRUE /*pretty_print_mergeinfo*/,
header_encoding,
outstream, errstream, changelists, ctx, pool);
}
svn_error_t *
svn_client_diff5(const apr_array_header_t *diff_options,
const char *path1,
@ -1057,6 +1148,53 @@ svn_client_diff(const apr_array_header_t *options,
outfile, errfile, ctx, pool);
}
svn_error_t *
svn_client_diff_peg6(const apr_array_header_t *options,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *start_revision,
const svn_opt_revision_t *end_revision,
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t no_diff_added,
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
svn_boolean_t ignore_properties,
svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
const char *header_encoding,
svn_stream_t *outstream,
svn_stream_t *errstream,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
return svn_client_diff_peg7(options,
path_or_url,
peg_revision,
start_revision,
end_revision,
relative_to_dir,
depth,
ignore_ancestry,
no_diff_added,
no_diff_deleted,
show_copies_as_adds,
ignore_content_type,
ignore_properties,
properties_only,
use_git_diff_format,
TRUE /*pretty_print_mergeinfo*/,
header_encoding,
outstream,
errstream,
changelists,
ctx,
pool);
}
svn_error_t *
svn_client_diff_peg5(const apr_array_header_t *diff_options,
const char *path,
@ -1643,7 +1781,7 @@ svn_client_log(const apr_array_header_t *targets,
* we just invoke the receiver manually on a hand-constructed log
* message for revision 0.
*
* See also http://subversion.tigris.org/issues/show_bug.cgi?id=692.
* See also https://issues.apache.org/jira/browse/SVN-692.
*/
if (err && (err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
&& (start->kind == svn_opt_revision_head)
@ -2852,6 +2990,22 @@ svn_client_resolved(const char *path,
svn_wc_conflict_choose_merged, ctx, pool);
}
/*** From revert.c ***/
svn_error_t *
svn_client_revert3(const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_boolean_t clear_changelists,
svn_boolean_t metadata_only,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
SVN_ERR(svn_client_revert4(paths, depth, changelists,
clear_changelists, metadata_only,
TRUE /*added_keep_local*/,
ctx, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_revert2(const apr_array_header_t *paths,
svn_depth_t depth,

File diff suppressed because it is too large Load Diff

View File

@ -647,20 +647,17 @@ do_dir_diff(const char *left_abspath,
}
svn_error_t *
svn_client__arbitrary_nodes_diff(const char **root_relpath,
svn_boolean_t *root_is_dir,
const char *left_abspath,
svn_client__arbitrary_nodes_diff(const char *left_abspath,
const char *right_abspath,
svn_depth_t depth,
const svn_diff_tree_processor_t *diff_processor,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_node_kind_t left_kind;
svn_node_kind_t right_kind;
const char *left_root_abspath;
const char *right_root_abspath;
const char *left_root_abspath = left_abspath;
const char *right_root_abspath = right_abspath;
svn_boolean_t left_before_right = TRUE; /* Future argument? */
if (depth == svn_depth_unknown)
@ -669,28 +666,6 @@ svn_client__arbitrary_nodes_diff(const char **root_relpath,
SVN_ERR(svn_io_check_resolved_path(left_abspath, &left_kind, scratch_pool));
SVN_ERR(svn_io_check_resolved_path(right_abspath, &right_kind, scratch_pool));
if (left_kind == svn_node_dir && right_kind == svn_node_dir)
{
left_root_abspath = left_abspath;
right_root_abspath = right_abspath;
if (root_relpath)
*root_relpath = "";
if (root_is_dir)
*root_is_dir = TRUE;
}
else
{
svn_dirent_split(&left_root_abspath, root_relpath, left_abspath,
scratch_pool);
right_root_abspath = svn_dirent_dirname(right_abspath, scratch_pool);
if (root_relpath)
*root_relpath = apr_pstrdup(result_pool, *root_relpath);
if (root_is_dir)
*root_is_dir = FALSE;
}
if (left_kind == svn_node_dir && right_kind == svn_node_dir)
{
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
@ -710,79 +685,48 @@ svn_client__arbitrary_nodes_diff(const char **root_relpath,
else if (left_kind == svn_node_file || left_kind == svn_node_dir
|| right_kind == svn_node_file || right_kind == svn_node_dir)
{
void *dir_baton;
svn_boolean_t skip = FALSE;
svn_boolean_t skip_children = FALSE;
svn_diff_source_t *left_src;
svn_diff_source_t *right_src;
left_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
right_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
/* The root is replaced... */
/* Report delete and/or add */
SVN_ERR(diff_processor->dir_opened(&dir_baton, &skip, &skip_children, "",
left_src,
right_src,
NULL /* copyfrom_src */,
NULL,
diff_processor,
scratch_pool, scratch_pool));
if (skip)
return SVN_NO_ERROR;
else if (!skip_children)
/* The root is added/deleted/replaced. Report delete and/or add. */
if (left_before_right)
{
if (left_before_right)
{
if (left_kind == svn_node_file)
SVN_ERR(do_file_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
else if (left_kind == svn_node_dir)
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, left_before_right,
depth, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
}
if (right_kind == svn_node_file)
if (left_kind == svn_node_file)
SVN_ERR(do_file_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
FALSE, TRUE, NULL /* parent_baton */,
TRUE, FALSE, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
else if (right_kind == svn_node_dir)
else if (left_kind == svn_node_dir)
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
FALSE, TRUE, left_before_right,
TRUE, FALSE, left_before_right,
depth, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
if (! left_before_right)
{
if (left_kind == svn_node_file)
SVN_ERR(do_file_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
else if (left_kind == svn_node_dir)
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, left_before_right,
depth, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
}
}
SVN_ERR(diff_processor->dir_closed("",
left_src,
right_src,
dir_baton,
diff_processor,
scratch_pool));
if (right_kind == svn_node_file)
SVN_ERR(do_file_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
FALSE, TRUE, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
else if (right_kind == svn_node_dir)
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
FALSE, TRUE, left_before_right,
depth, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
if (! left_before_right)
{
if (left_kind == svn_node_file)
SVN_ERR(do_file_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
else if (left_kind == svn_node_dir)
SVN_ERR(do_dir_diff(left_abspath, right_abspath,
left_root_abspath, right_root_abspath,
TRUE, FALSE, left_before_right,
depth, NULL /* parent_baton */,
diff_processor, ctx, scratch_pool));
}
}
else
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,

View File

@ -36,11 +36,6 @@
/* Diff callbacks baton. */
struct summarize_baton_t {
apr_pool_t *baton_pool; /* For allocating skip_path */
/* The target path of the diff, relative to the anchor; "" if target == anchor. */
const char *skip_relpath;
/* The summarize callback passed down from the API */
svn_client_diff_summarize_func_t summarize_func;
@ -49,9 +44,8 @@ struct summarize_baton_t {
};
/* Call B->summarize_func with B->summarize_func_baton, passing it a
* summary object composed from PATH (but made to be relative to the target
* of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an
* add or delete) and NODE_KIND. */
* summary object composed from PATH, SUMMARIZE_KIND, PROP_CHANGED (or
* FALSE if the action is an add or delete) and NODE_KIND. */
static svn_error_t *
send_summary(struct summarize_baton_t *b,
const char *path,
@ -65,9 +59,7 @@ send_summary(struct summarize_baton_t *b,
SVN_ERR_ASSERT(summarize_kind != svn_client_diff_summarize_kind_normal
|| prop_changed);
/* PATH is relative to the anchor of the diff, but SUM->path needs to be
relative to the target of the diff. */
sum->path = svn_relpath_skip_ancestor(b->skip_relpath, path);
sum->path = path;
sum->summarize_kind = summarize_kind;
if (summarize_kind == svn_client_diff_summarize_kind_modified
|| summarize_kind == svn_client_diff_summarize_kind_normal)
@ -265,18 +257,15 @@ diff_file_deleted(const char *relpath,
svn_error_t *
svn_client__get_diff_summarize_callbacks(
const svn_diff_tree_processor_t **diff_processor,
const char ***p_root_relpath,
svn_diff_tree_processor_t **diff_processor,
svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
const char *original_target,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_diff_tree_processor_t *dp;
struct summarize_baton_t *b = apr_pcalloc(result_pool, sizeof(*b));
b->baton_pool = result_pool;
b->summarize_func = summarize_func;
b->summarize_func_baton = summarize_baton;
@ -293,7 +282,6 @@ svn_client__get_diff_summarize_callbacks(
dp->dir_added = diff_dir_added;
*diff_processor = dp;
*p_root_relpath = &b->skip_relpath;
return SVN_NO_ERROR;
}

View File

@ -453,12 +453,12 @@ export_node(void *baton,
* If PATH exists but is a file, then error with SVN_ERR_WC_NOT_WORKING_COPY.
*
* If PATH is a already a directory, then error with
* SVN_ERR_WC_OBSTRUCTED_UPDATE, unless FORCE, in which case just
* SVN_ERR_WC_OBSTRUCTED_UPDATE, unless OVERWRITE, in which case just
* export into PATH with no error.
*/
static svn_error_t *
open_root_internal(const char *path,
svn_boolean_t force,
svn_boolean_t overwrite,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *pool)
@ -472,7 +472,7 @@ open_root_internal(const char *path,
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
_("'%s' exists and is not a directory"),
svn_dirent_local_style(path, pool));
else if ((kind != svn_node_dir) || (! force))
else if ((kind != svn_node_dir) || (! overwrite))
return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("'%s' already exists"),
svn_dirent_local_style(path, pool));
@ -501,7 +501,7 @@ struct edit_baton
const char *repos_root_url;
const char *root_path;
const char *root_url;
svn_boolean_t force;
svn_boolean_t overwrite;
svn_revnum_t *target_revision;
apr_hash_t *externals;
const char *native_eol;
@ -587,7 +587,7 @@ open_root(void *edit_baton,
struct edit_baton *eb = edit_baton;
struct dir_baton *db = apr_pcalloc(pool, sizeof(*db));
SVN_ERR(open_root_internal(eb->root_path, eb->force,
SVN_ERR(open_root_internal(eb->root_path, eb->overwrite,
eb->notify_func, eb->notify_baton, pool));
/* Build our dir baton. */
@ -621,7 +621,7 @@ add_directory(const char *path,
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
_("'%s' exists and is not a directory"),
svn_dirent_local_style(full_path, pool));
else if (! (kind == svn_node_dir && eb->force))
else if (! (kind == svn_node_dir && eb->overwrite))
return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("'%s' already exists"),
svn_dirent_local_style(full_path, pool));
@ -1077,7 +1077,7 @@ add_directory_ev2(void *baton,
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
_("'%s' exists and is not a directory"),
svn_dirent_local_style(full_path, scratch_pool));
else if (! (kind == svn_node_dir && eb->force))
else if (! (kind == svn_node_dir && eb->overwrite))
return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("'%s' already exists"),
svn_dirent_local_style(full_path, scratch_pool));
@ -1141,7 +1141,7 @@ get_editor_ev2(const svn_delta_editor_t **export_editor,
exb, result_pool));
/* Create the root of the export. */
SVN_ERR(open_root_internal(eb->root_path, eb->force, eb->notify_func,
SVN_ERR(open_root_internal(eb->root_path, eb->overwrite, eb->notify_func,
eb->notify_baton, scratch_pool));
return SVN_NO_ERROR;
@ -1153,7 +1153,6 @@ export_file_ev2(const char *from_url,
struct edit_baton *eb,
svn_client__pathrev_t *loc,
svn_ra_session_t *ra_session,
svn_boolean_t overwrite,
apr_pool_t *scratch_pool)
{
apr_hash_t *props;
@ -1177,7 +1176,7 @@ export_file_ev2(const char *from_url,
SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
! overwrite)
! eb->overwrite)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("Destination file '%s' exists, and "
"will not be overwritten unless forced"),
@ -1207,7 +1206,6 @@ export_file(const char *from_url,
struct edit_baton *eb,
svn_client__pathrev_t *loc,
svn_ra_session_t *ra_session,
svn_boolean_t overwrite,
apr_pool_t *scratch_pool)
{
apr_hash_t *props;
@ -1232,7 +1230,7 @@ export_file(const char *from_url,
SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
! overwrite)
! eb->overwrite)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("Destination file '%s' exists, and "
"will not be overwritten unless forced"),
@ -1289,7 +1287,6 @@ export_directory(const char *from_url,
struct edit_baton *eb,
svn_client__pathrev_t *loc,
svn_ra_session_t *ra_session,
svn_boolean_t overwrite,
svn_boolean_t ignore_externals,
svn_boolean_t ignore_keywords,
svn_depth_t depth,
@ -1344,7 +1341,7 @@ export_directory(const char *from_url,
SVN_ERR(svn_io_check_path(to_path, &kind, scratch_pool));
if (kind == svn_node_none)
SVN_ERR(open_root_internal
(to_path, overwrite, ctx->notify_func2,
(to_path, eb->overwrite, ctx->notify_func2,
ctx->notify_baton2, scratch_pool));
if (! ignore_externals && depth == svn_depth_infinity)
@ -1415,7 +1412,7 @@ svn_client_export5(svn_revnum_t *result_rev,
SVN_ERR(svn_ra_get_repos_root2(ra_session, &eb->repos_root_url, pool));
eb->root_path = to_path;
eb->root_url = loc->url;
eb->force = overwrite;
eb->overwrite = overwrite;
eb->target_revision = &edit_revision;
eb->externals = apr_hash_make(pool);
eb->native_eol = native_eol;
@ -1431,15 +1428,15 @@ svn_client_export5(svn_revnum_t *result_rev,
{
if (!ENABLE_EV2_IMPL)
SVN_ERR(export_file(from_url, to_path, eb, loc, ra_session,
overwrite, pool));
pool));
else
SVN_ERR(export_file_ev2(from_url, to_path, eb, loc,
ra_session, overwrite, pool));
ra_session, pool));
}
else if (kind == svn_node_dir)
{
SVN_ERR(export_directory(from_url, to_path,
eb, loc, ra_session, overwrite,
eb, loc, ra_session,
ignore_externals, ignore_keywords, depth,
native_eol, ctx, pool));
}

View File

@ -167,7 +167,8 @@ build_info_from_dirent(svn_client_info2_t **info,
#define DIRENT_FIELDS (SVN_DIRENT_KIND | \
SVN_DIRENT_CREATED_REV | \
SVN_DIRENT_TIME | \
SVN_DIRENT_LAST_AUTHOR)
SVN_DIRENT_LAST_AUTHOR | \
SVN_DIRENT_SIZE)
/* Helper func for recursively fetching svn_dirent_t's from a remote
@ -267,6 +268,7 @@ same_resource_in_head(svn_boolean_t *same_p,
ctx, pool);
if (err &&
((err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) ||
(err->apr_err == SVN_ERR_FS_NOT_DIRECTORY) ||
(err->apr_err == SVN_ERR_FS_NOT_FOUND)))
{
svn_error_clear(err);

View File

@ -0,0 +1,289 @@
/*
* layout.c: code to list and update the working copy layout
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include "svn_hash.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_error.h"
#include "svn_pools.h"
#include "client.h"
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
struct layout_item_t
{
const char *local_abspath;
const char *url;
svn_revnum_t revision;
svn_depth_t depth;
struct layout_item_t *ancestor;
apr_pool_t *pool;
};
struct client_layout_baton_t
{
const char *root_abspath;
svn_wc_context_t *wc_ctx;
const char *repos_root_url;
struct layout_item_t *stack;
apr_pool_t *root_pool;
svn_client__layout_func_t layout;
void *layout_baton;
};
static svn_error_t *
layout_set_path(void *report_baton,
const char *path,
svn_revnum_t revision,
svn_depth_t depth,
svn_boolean_t start_empty,
const char *lock_token,
apr_pool_t *pool)
{
struct client_layout_baton_t *lb = report_baton;
const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
struct layout_item_t *it;
apr_pool_t *item_pool;
svn_depth_t expected_depth;
while (lb->stack
&& !svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
{
it = lb->stack;
lb->stack = it->ancestor;
svn_pool_destroy(it->pool);
}
item_pool = svn_pool_create(lb->stack ? lb->stack->pool
: lb->root_pool);
it = apr_pcalloc(item_pool, sizeof(*it));
it->pool = item_pool;
it->local_abspath = apr_pstrdup(item_pool, local_abspath);
it->depth = depth;
it->revision = revision;
if (lb->stack)
{
it->url = svn_path_url_add_component2(
lb->stack->url,
svn_dirent_skip_ancestor(lb->stack->local_abspath,
local_abspath),
item_pool);
}
else
{
const char *repos_relpath, *repos_root_url;
SVN_ERR(svn_wc__node_get_base(NULL, NULL, &repos_relpath,
&repos_root_url, NULL, NULL,
lb->wc_ctx, local_abspath,
FALSE /* ignore_enoent */,
pool, pool));
lb->repos_root_url = apr_pstrdup(lb->root_pool, repos_root_url);
it->url = svn_path_url_add_component2(repos_root_url, repos_relpath,
item_pool);
}
it->ancestor = lb->stack;
lb->stack = it;
if (!it->ancestor)
expected_depth = depth;
else if (it->ancestor->depth == svn_depth_infinity)
expected_depth = svn_depth_infinity;
else
expected_depth = svn_depth_empty;
return svn_error_trace(lb->layout(lb->layout_baton,
it->local_abspath,
lb->repos_root_url,
FALSE /* not-present */,
FALSE /* url changed */,
it->url,
it->ancestor
? it->ancestor->revision != it->revision
: FALSE,
it->revision,
(depth != expected_depth),
it->depth,
pool));
}
static svn_error_t *
layout_link_path(void *report_baton,
const char *path,
const char *url,
svn_revnum_t revision,
svn_depth_t depth,
svn_boolean_t start_empty,
const char *lock_token,
apr_pool_t *pool)
{
struct client_layout_baton_t *lb = report_baton;
const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
struct layout_item_t *it;
apr_pool_t *item_pool;
svn_depth_t expected_depth;
SVN_ERR_ASSERT(lb->stack); /* Always below root entry */
while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
{
it = lb->stack;
lb->stack = it->ancestor;
svn_pool_destroy(it->pool);
}
item_pool = svn_pool_create(lb->stack ? lb->stack->pool
: lb->root_pool);
it = apr_pcalloc(item_pool, sizeof(*it));
it->pool = item_pool;
it->local_abspath = apr_pstrdup(item_pool, local_abspath);
it->depth = depth;
it->revision = revision;
it->url = apr_pstrdup(item_pool, url);
it->ancestor = lb->stack;
lb->stack = it;
if (it->ancestor->depth == svn_depth_infinity)
expected_depth = svn_depth_infinity;
else
expected_depth = svn_depth_empty;
return svn_error_trace(lb->layout(lb->layout_baton,
it->local_abspath,
lb->repos_root_url,
FALSE /* not-present */,
TRUE /* url changed */,
it->url,
it->ancestor
? it->ancestor->revision != it->revision
: FALSE,
it->revision,
(depth != expected_depth),
it->depth,
pool));
}
static svn_error_t *
layout_delete_path(void *report_baton,
const char *path,
apr_pool_t *pool)
{
struct client_layout_baton_t *lb = report_baton;
const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool);
struct layout_item_t *it;
SVN_ERR_ASSERT(lb->stack); /* Always below root entry */
while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath))
{
it = lb->stack;
lb->stack = it->ancestor;
svn_pool_destroy(it->pool);
}
return svn_error_trace(lb->layout(lb->layout_baton,
local_abspath,
lb->repos_root_url,
TRUE /* not-present */,
FALSE /* url changed */,
NULL /* no-url */,
FALSE /* revision changed */,
SVN_INVALID_REVNUM,
FALSE /* depth changed */,
svn_depth_unknown,
pool));
}
static svn_error_t *
layout_finish_report(void *report_baton,
apr_pool_t *pool)
{
/*struct client_layout_baton_t *lb = report_baton;*/
return SVN_NO_ERROR;
}
static svn_error_t *
layout_abort_report(void *report_baton,
apr_pool_t *pool)
{
/*struct client_layout_baton_t *lb = report_baton;*/
return SVN_NO_ERROR;
}
static const svn_ra_reporter3_t layout_reporter =
{
layout_set_path,
layout_delete_path,
layout_link_path,
layout_finish_report,
layout_abort_report
};
svn_error_t *
svn_client__layout_list(const char *local_abspath,
svn_client__layout_func_t layout,
void *layout_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
struct client_layout_baton_t lb;
lb.root_abspath = local_abspath;
lb.root_pool = scratch_pool;
lb.wc_ctx = ctx->wc_ctx;
lb.repos_root_url = NULL; /* Filled in later */
lb.stack = NULL;
lb.layout = layout;
lb.layout_baton = layout_baton;
/* Drive the reporter structure, describing the revisions within
LOCAL_ABSPATH. */
SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath,
&layout_reporter, &lb,
FALSE /* restore_files */,
svn_depth_infinity,
TRUE /* honor_depth_exclude */,
FALSE /* depth_compatibility_trick */,
FALSE /* use_commit_times */,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
scratch_pool));
return SVN_NO_ERROR;
}

View File

@ -6,7 +6,7 @@ includedir=@includedir@
Name: libsvn_client
Description: Subversion Client Library
Version: @PACKAGE_VERSION@
Requires: apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_wc libsvn_ra libsvn_delta libsvn_diff libsvn_subr
Libs: -L${libdir} -lsvn_client
Cflags: -I${includedir}
Requires: apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_wc, libsvn_ra, libsvn_delta, libsvn_diff, libsvn_subr
Libs: -L${libdir} -lsvn_client-1
Cflags: -I${includedir}/subversion-1

View File

@ -394,7 +394,7 @@ list_internal(const char *path_or_url,
svn_membuf__create(&scratch_buffer, 256, pool);
/* Report the dirent for the target. */
if (match_patterns(svn_dirent_dirname(fs_path, pool), patterns,
if (match_patterns(svn_dirent_basename(fs_path, pool), patterns,
&scratch_buffer))
SVN_ERR(list_func(baton, "", dirent, locks
? (svn_hash_gets(locks, fs_path))

View File

@ -215,6 +215,21 @@
/*** Repos-Diff Editor Callbacks ***/
struct merge_cmd_baton_t;
struct notify_begin_state_t
{
/* Cache of which abspath was last notified. */
const char *last_abspath;
/* Reference to the main merge baton */
struct merge_cmd_baton_t *merge_b;
/* the wrapped notification callback */
svn_wc_notify_func2_t notify_func2;
void *notify_baton2;
};
typedef struct merge_cmd_baton_t {
svn_boolean_t force_delete; /* Delete a file/dir even if modified */
svn_boolean_t dry_run;
@ -242,11 +257,15 @@ typedef struct merge_cmd_baton_t {
/* Rangelist containing single range which describes the gap, if any,
in the natural history of the merge source currently being processed.
See http://subversion.tigris.org/issues/show_bug.cgi?id=3432.
See https://issues.apache.org/jira/browse/SVN-3432.
Updated during each call to do_directory_merge(). May be NULL if there
is no gap. */
svn_rangelist_t *implicit_src_gap;
/* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
comment) or a similar list for single-file-merges */
const apr_array_header_t *children_with_mergeinfo;
svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */
/* The list of any paths which remained in conflict after a
@ -319,17 +338,10 @@ typedef struct merge_cmd_baton_t {
or do_file_merge() in do_merge(). */
apr_pool_t *pool;
/* State for notify_merge_begin() */
struct notify_begin_state_t
{
/* Cache of which abspath was last notified. */
const char *last_abspath;
/* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
comment) or a similar list for single-file-merges */
const apr_array_header_t *nodes_with_mergeinfo;
} notify_begin;
/* Our notification callback, that adds a 'begin' notification */
svn_wc_notify_func2_t notify_func;
void *notify_baton;
struct notify_begin_state_t notify_begin;
} merge_cmd_baton_t;
@ -340,17 +352,25 @@ typedef struct merge_cmd_baton_t {
merge source is an ancestor of the right-side (or vice-versa), the merge
source is in the same repository as the merge target, and we are not
ignoring mergeinfo. */
#define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable \
&& (merge_b)->merge_source.ancestral \
&& (merge_b)->same_repos \
&& (! (merge_b)->ignore_mergeinfo))
static svn_boolean_t
HONOR_MERGEINFO(const merge_cmd_baton_t *merge_b)
{
return (merge_b->mergeinfo_capable
&& merge_b->merge_source.ancestral
&& merge_b->same_repos
&& (!merge_b->ignore_mergeinfo));
}
/* Return TRUE iff we should be recording mergeinfo for the merge described
by MERGE_B. Specifically, that is if we are honoring mergeinfo and the
merge is not a dry run. */
#define RECORD_MERGEINFO(merge_b) (HONOR_MERGEINFO(merge_b) \
&& !(merge_b)->dry_run)
static svn_boolean_t
RECORD_MERGEINFO(const merge_cmd_baton_t *merge_b)
{
return (HONOR_MERGEINFO(merge_b)
&& !merge_b->dry_run);
}
/*-----------------------------------------------------------------------*/
@ -1226,13 +1246,6 @@ struct merge_file_baton_t
svn_boolean_t add_is_replace; /* Add is second part of replace */
};
/* Forward declaration */
static svn_error_t *
notify_merge_begin(merge_cmd_baton_t *merge_b,
const char *local_abspath,
svn_boolean_t delete_action,
apr_pool_t *scratch_pool);
/* Record the skip for future processing and (later) produce the
skip notification */
static svn_error_t *
@ -1253,18 +1266,16 @@ record_skip(merge_cmd_baton_t *merge_b,
store_path(merge_b->skipped_abspaths, local_abspath);
}
if (merge_b->ctx->notify_func2)
if (merge_b->notify_func)
{
svn_wc_notify_t *notify;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
notify->kind = kind;
notify->content_state = notify->prop_state = state;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton, notify,
scratch_pool);
}
return SVN_NO_ERROR;
}
@ -1364,7 +1375,7 @@ record_tree_conflict(merge_cmd_baton_t *merge_b,
* but figure out the actual revision range merged. */
(void)find_nearest_ancestor_with_intersecting_ranges(
&(range.start), &(range.end),
merge_b->notify_begin.nodes_with_mergeinfo,
merge_b->children_with_mergeinfo,
action != svn_wc_conflict_action_delete,
local_abspath);
loc1 = svn_client__pathrev_dup(merge_b->merge_source.loc1,
@ -1423,18 +1434,16 @@ record_tree_conflict(merge_cmd_baton_t *merge_b,
}
/* On a replacement we currently get two tree conflicts */
if (merge_b->ctx->notify_func2 && notify_tc)
if (merge_b->notify_func && notify_tc)
{
svn_wc_notify_t *notify;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict,
scratch_pool);
notify->kind = local_node_kind;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton, notify,
scratch_pool);
}
return SVN_NO_ERROR;
@ -1455,21 +1464,19 @@ record_update_add(merge_cmd_baton_t *merge_b,
store_path(merge_b->merged_abspaths, local_abspath);
}
if (merge_b->ctx->notify_func2)
if (merge_b->notify_func)
{
svn_wc_notify_t *notify;
svn_wc_notify_action_t action = svn_wc_notify_update_add;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
if (notify_replaced)
action = svn_wc_notify_update_replace;
notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
notify->kind = kind;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton, notify,
scratch_pool);
}
return SVN_NO_ERROR;
@ -1490,20 +1497,18 @@ record_update_update(merge_cmd_baton_t *merge_b,
store_path(merge_b->merged_abspaths, local_abspath);
}
if (merge_b->ctx->notify_func2)
if (merge_b->notify_func)
{
svn_wc_notify_t *notify;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update,
scratch_pool);
notify->kind = kind;
notify->content_state = content_state;
notify->prop_state = prop_state;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton, notify,
scratch_pool);
}
return SVN_NO_ERROR;
@ -1529,8 +1534,6 @@ record_update_delete(merge_cmd_baton_t *merge_b,
store_path(merge_b->merged_abspaths, local_abspath);
}
SVN_ERR(notify_merge_begin(merge_b, local_abspath, TRUE, scratch_pool));
if (parent_db)
{
const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath);
@ -1552,7 +1555,7 @@ handle_pending_notifications(merge_cmd_baton_t *merge_b,
struct merge_dir_baton_t *db,
apr_pool_t *scratch_pool)
{
if (merge_b->ctx->notify_func2 && db->pending_deletes)
if (merge_b->notify_func && db->pending_deletes)
{
apr_hash_index_t *hi;
@ -1569,8 +1572,8 @@ handle_pending_notifications(merge_cmd_baton_t *merge_b,
notify->kind = svn_node_kind_from_word(
apr_hash_this_val(hi));
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
notify, scratch_pool);
merge_b->notify_func(merge_b->notify_baton,
notify, scratch_pool);
}
db->pending_deletes = NULL;
@ -1620,13 +1623,10 @@ mark_dir_edited(merge_cmd_baton_t *merge_b,
for clarity we produce a skip for this node that
most likely isn't touched by the merge itself */
if (merge_b->ctx->notify_func2)
if (merge_b->notify_func)
{
svn_wc_notify_t *notify;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
scratch_pool));
notify = svn_wc_create_notify(
local_abspath,
(db->tree_conflict_reason == CONFLICT_REASON_SKIP)
@ -1636,9 +1636,9 @@ mark_dir_edited(merge_cmd_baton_t *merge_b,
notify->kind = svn_node_dir;
notify->content_state = notify->prop_state = db->skip_reason;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton,
notify,
scratch_pool);
}
if (merge_b->merge_source.ancestral
@ -1706,21 +1706,18 @@ mark_file_edited(merge_cmd_baton_t *merge_b,
for clarity we produce a skip for this node that
most likely isn't touched by the merge itself */
if (merge_b->ctx->notify_func2)
if (merge_b->notify_func)
{
svn_wc_notify_t *notify;
SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
scratch_pool));
notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip,
scratch_pool);
notify->kind = svn_node_file;
notify->content_state = notify->prop_state = fb->skip_reason;
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
notify,
scratch_pool);
merge_b->notify_func(merge_b->notify_baton,
notify,
scratch_pool);
}
if (merge_b->merge_source.ancestral
@ -3413,6 +3410,49 @@ merge_node_absent(const char *relpath,
return SVN_NO_ERROR;
}
/* Return a diff processor that will apply the merge to the WC.
*/
static svn_diff_tree_processor_t *
merge_apply_processor(merge_cmd_baton_t *merge_cmd_baton,
apr_pool_t *result_pool)
{
svn_diff_tree_processor_t *merge_processor;
merge_processor = svn_diff__tree_processor_create(merge_cmd_baton,
result_pool);
merge_processor->dir_opened = merge_dir_opened;
merge_processor->dir_changed = merge_dir_changed;
merge_processor->dir_added = merge_dir_added;
merge_processor->dir_deleted = merge_dir_deleted;
merge_processor->dir_closed = merge_dir_closed;
merge_processor->file_opened = merge_file_opened;
merge_processor->file_changed = merge_file_changed;
merge_processor->file_added = merge_file_added;
merge_processor->file_deleted = merge_file_deleted;
/* Not interested in file_closed() */
merge_processor->node_absent = merge_node_absent;
return merge_processor;
}
/* Initialize minimal dir baton to allow calculating 'R'eplace
from 'D'elete + 'A'dd. */
static void *
open_dir_for_replace_single_file(apr_pool_t *result_pool)
{
struct merge_dir_baton_t *dir_baton = apr_pcalloc(result_pool, sizeof(*dir_baton));
dir_baton->pool = result_pool;
dir_baton->tree_conflict_reason = CONFLICT_REASON_NONE;
dir_baton->tree_conflict_action = svn_wc_conflict_action_edit;
dir_baton->skip_reason = svn_wc_notify_state_unknown;
return dir_baton;
}
/*-----------------------------------------------------------------------*/
/*** Merge Notification ***/
@ -3608,20 +3648,9 @@ notify_merge_completed(const char *target_abspath,
}
}
/* Is the notification the result of a real operative merge? */
#define IS_OPERATIVE_NOTIFICATION(notify) \
(notify->content_state == svn_wc_notify_state_conflicted \
|| notify->content_state == svn_wc_notify_state_merged \
|| notify->content_state == svn_wc_notify_state_changed \
|| notify->prop_state == svn_wc_notify_state_conflicted \
|| notify->prop_state == svn_wc_notify_state_merged \
|| notify->prop_state == svn_wc_notify_state_changed \
|| notify->action == svn_wc_notify_update_add \
|| notify->action == svn_wc_notify_tree_conflict)
/* Remove merge source gaps from range used for merge notifications.
See http://subversion.tigris.org/issues/show_bug.cgi?id=4138
See https://issues.apache.org/jira/browse/SVN-4138
If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a
single range (see the implicit_src_gap member of merge_cmd_baton_t).
@ -3656,27 +3685,28 @@ remove_source_gap(svn_merge_range_t *range,
* This calls the client's notification receiver (as found in the client
* context), with a WC abspath.
*/
static svn_error_t *
notify_merge_begin(merge_cmd_baton_t *merge_b,
static void
notify_merge_begin(struct notify_begin_state_t *notify_begin_state,
const char *local_abspath,
svn_boolean_t delete_action,
apr_pool_t *scratch_pool)
{
merge_cmd_baton_t *merge_b = notify_begin_state->merge_b;
svn_wc_notify_t *notify;
svn_merge_range_t n_range =
{SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE};
const char *notify_abspath;
if (! merge_b->ctx->notify_func2)
return SVN_NO_ERROR;
if (! notify_begin_state->notify_func2)
return;
/* If our merge sources are ancestors of one another... */
if (merge_b->merge_source.ancestral)
{
const svn_client__merge_path_t *child;
/* Find NOTIFY->PATH's nearest ancestor in
NOTIFY->CHILDREN_WITH_MERGEINFO. Normally we consider a child in
NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an
/* Find LOCAL_ABSPATH's nearest ancestor in
CHILDREN_WITH_MERGEINFO. Normally we consider a child in
CHILDREN_WITH_MERGEINFO representing PATH to be an
ancestor of PATH, but if this is a deletion of PATH then the
notification must be for a proper ancestor of PATH. This ensures
we don't get notifications like:
@ -3692,47 +3722,47 @@ notify_merge_begin(merge_cmd_baton_t *merge_b,
child = find_nearest_ancestor_with_intersecting_ranges(
&(n_range.start), &(n_range.end),
merge_b->notify_begin.nodes_with_mergeinfo,
merge_b->children_with_mergeinfo,
! delete_action, local_abspath);
if (!child && delete_action)
{
/* Triggered by file replace in single-file-merge */
child = find_nearest_ancestor(merge_b->notify_begin.nodes_with_mergeinfo,
child = find_nearest_ancestor(merge_b->children_with_mergeinfo,
TRUE, local_abspath);
}
assert(child != NULL); /* Should always find the merge anchor */
if (! child)
return SVN_NO_ERROR;
return;
if (merge_b->notify_begin.last_abspath != NULL
&& strcmp(child->abspath, merge_b->notify_begin.last_abspath) == 0)
if (notify_begin_state->last_abspath != NULL
&& strcmp(child->abspath, notify_begin_state->last_abspath) == 0)
{
/* Don't notify the same merge again */
return SVN_NO_ERROR;
return;
}
merge_b->notify_begin.last_abspath = child->abspath;
notify_begin_state->last_abspath = child->abspath;
if (child->absent || child->remaining_ranges->nelts == 0
|| !SVN_IS_VALID_REVNUM(n_range.start))
{
/* No valid information for an header */
return SVN_NO_ERROR;
return;
}
notify_abspath = child->abspath;
}
else
{
if (merge_b->notify_begin.last_abspath)
return SVN_NO_ERROR; /* already notified */
if (notify_begin_state->last_abspath)
return; /* already notified */
notify_abspath = merge_b->target->abspath;
/* Store something in last_abspath. Any value would do */
merge_b->notify_begin.last_abspath = merge_b->target->abspath;
notify_begin_state->last_abspath = merge_b->target->abspath;
}
notify = svn_wc_create_notify(notify_abspath,
@ -3753,10 +3783,23 @@ notify_merge_begin(merge_cmd_baton_t *merge_b,
notify->merge_range = NULL;
}
merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
scratch_pool);
notify_begin_state->notify_func2(notify_begin_state->notify_baton2, notify,
scratch_pool);
}
return SVN_NO_ERROR;
/* Our notification callback, that adds a 'begin' notification */
static void
notify_merging(void *baton,
const svn_wc_notify_t *notify,
apr_pool_t *pool)
{
struct notify_begin_state_t *b = baton;
notify_merge_begin(b, notify->path,
notify->action == svn_wc_notify_update_delete,
pool);
b->notify_func2(b->notify_baton2, notify, pool);
}
/* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple
@ -5445,7 +5488,7 @@ record_skips_in_mergeinfo(const char *mergeinfo_path,
### TODO: An empty range is fine if the skipped path doesn't
### inherit any mergeinfo from a parent, but if it does
### we need to account for that. See issue #3440
### http://subversion.tigris.org/issues/show_bug.cgi?id=3440. */
### https://issues.apache.org/jira/browse/SVN-3440. */
svn_hash_sets(merges, skipped_abspath,
apr_array_make(scratch_pool, 0,
sizeof(svn_merge_range_t *)));
@ -5554,7 +5597,7 @@ svn_client__make_merge_conflict_error(svn_client__conflict_report_t *report,
defined in get_mergeinfo_paths(). Remove any paths absent from disk
or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to
or are descendants of TARGET_WCPATH by setting those children to NULL. */
static void
static svn_error_t *
remove_absent_children(const char *target_wcpath,
apr_array_header_t *children_with_mergeinfo)
{
@ -5569,9 +5612,10 @@ remove_absent_children(const char *target_wcpath,
if ((child->absent || child->scheduled_for_deletion)
&& svn_dirent_is_ancestor(target_wcpath, child->abspath))
{
svn_sort__array_delete(children_with_mergeinfo, i--, 1);
SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1));
}
}
return SVN_NO_ERROR;
}
/* Helper for do_directory_merge() to handle the case where a merge editor
@ -5586,14 +5630,14 @@ remove_absent_children(const char *target_wcpath,
MERGE_B->target->abspath, this must always be present in
CHILDREN_WITH_MERGEINFO so this is never removed by this
function. */
static void
static svn_error_t *
remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b,
apr_array_header_t *children_with_mergeinfo)
{
int i;
if (!merge_b->paths_with_deleted_mergeinfo)
return;
return SVN_NO_ERROR;
/* CHILDREN_WITH_MERGEINFO[0] is the always the merge target
so start at the first child. */
@ -5604,9 +5648,10 @@ remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b,
if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath))
{
svn_sort__array_delete(children_with_mergeinfo, i--, 1);
SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1));
}
}
return SVN_NO_ERROR;
}
/* Helper for do_directory_merge().
@ -5932,7 +5977,7 @@ get_most_inclusive_rev(const apr_array_header_t *children_with_mergeinfo,
remaining_ranges is inclusive of END_REV, Slice the first range in
to two at END_REV. All the allocations are persistent and allocated
from POOL. */
static void
static svn_error_t *
slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
svn_boolean_t is_rollback, svn_revnum_t end_rev,
apr_pool_t *pool)
@ -5962,10 +6007,12 @@ slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
split_range2->start = end_rev;
APR_ARRAY_IDX(child->remaining_ranges, 0,
svn_merge_range_t *) = split_range1;
svn_sort__array_insert(child->remaining_ranges, &split_range2, 1);
SVN_ERR(svn_sort__array_insert2(child->remaining_ranges,
&split_range2, 1));
}
}
}
return SVN_NO_ERROR;
}
/* Helper for do_directory_merge().
@ -5977,7 +6024,7 @@ slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
If a range is removed from a child's remaining_ranges array, allocate the
new remaining_ranges array in POOL.
*/
static void
static svn_error_t *
remove_first_range_from_remaining_ranges(svn_revnum_t revision,
apr_array_header_t
*children_with_mergeinfo,
@ -5998,10 +6045,11 @@ remove_first_range_from_remaining_ranges(svn_revnum_t revision,
APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
if (first_range->end == revision)
{
svn_sort__array_delete(child->remaining_ranges, 0, 1);
SVN_ERR(svn_sort__array_delete2(child->remaining_ranges, 0, 1));
}
}
}
return SVN_NO_ERROR;
}
/* Get a file's content and properties from the repository.
@ -6087,7 +6135,7 @@ get_child_with_mergeinfo(const apr_array_header_t *children_with_mergeinfo,
out of order and then sort afterwards. (One caller is doing a qsort
after calling this anyway.)
*/
static void
static svn_error_t *
insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
const svn_client__merge_path_t *insert_element,
apr_pool_t *pool)
@ -6101,7 +6149,9 @@ insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
compare_merge_path_t_as_paths);
new_element = svn_client__merge_path_dup(insert_element, pool);
svn_sort__array_insert(children_with_mergeinfo, &new_element, insert_index);
SVN_ERR(svn_sort__array_insert2(children_with_mergeinfo,
&new_element, insert_index));
return SVN_NO_ERROR;
}
/* Helper for get_mergeinfo_paths().
@ -6162,7 +6212,7 @@ insert_parent_and_sibs_of_sw_absent_del_subtree(
parent->missing_child = child->absent;
parent->switched_child = child->switched;
/* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
insert_child_to_merge(children_with_mergeinfo, parent, pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo, parent, pool));
/* Increment for loop index so we don't process the inserted element. */
(*curr_index)++;
} /*(parent == NULL) */
@ -6199,8 +6249,8 @@ insert_parent_and_sibs_of_sw_absent_del_subtree(
sibling_of_missing = svn_client__merge_path_create(child_abspath,
pool);
insert_child_to_merge(children_with_mergeinfo, sibling_of_missing,
pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
sibling_of_missing, pool));
}
}
@ -6541,8 +6591,8 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
svn_client__merge_path_t *switched_child =
svn_client__merge_path_create(wc_path, result_pool);
switched_child->switched = TRUE;
insert_child_to_merge(children_with_mergeinfo, switched_child,
result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
switched_child, result_pool));
}
}
}
@ -6594,8 +6644,8 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
}
if (new_shallow_child)
insert_child_to_merge(children_with_mergeinfo, shallow_child,
result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
shallow_child, result_pool));
}
}
@ -6624,8 +6674,8 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
svn_client__merge_path_t *absent_child =
svn_client__merge_path_create(wc_path, result_pool);
absent_child->absent = TRUE;
insert_child_to_merge(children_with_mergeinfo, absent_child,
result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
absent_child, result_pool));
}
}
}
@ -6638,8 +6688,8 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
svn_client__merge_path_t *target_child =
svn_client__merge_path_create(target->abspath,
result_pool);
insert_child_to_merge(children_with_mergeinfo, target_child,
result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo, target_child,
result_pool));
}
/* Case 8: Path is an immediate *directory* child of
@ -6682,8 +6732,8 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
&& depth == svn_depth_immediates)
immediate_child->immediate_child_dir = TRUE;
insert_child_to_merge(children_with_mergeinfo,
immediate_child, result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
immediate_child, result_pool));
}
}
}
@ -6775,9 +6825,9 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
child_of_noninheritable =
svn_client__merge_path_create(child_abspath, result_pool);
child_of_noninheritable->child_of_noninheritable = TRUE;
insert_child_to_merge(children_with_mergeinfo,
child_of_noninheritable,
result_pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
child_of_noninheritable,
result_pool));
if (!dry_run && same_repos)
{
svn_mergeinfo_t mergeinfo;
@ -7201,7 +7251,7 @@ normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
new_segment->path = original_repos_relpath;
new_segment->range_start = original_revision;
new_segment->range_end = original_revision;
svn_sort__array_insert(segments, &new_segment, 0);
SVN_ERR(svn_sort__array_insert2(segments, &new_segment, 0));
}
}
}
@ -7596,16 +7646,15 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
/* ### Create a fake copy of merge_target as we don't keep
remaining_ranges in sync (yet). */
target_info = apr_pcalloc(scratch_pool, sizeof(*target_info));
target_info->abspath = merge_target->abspath;
target_info = svn_client__merge_path_create(merge_target->abspath,
scratch_pool);
target_info->remaining_ranges = ranges_to_merge;
APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *)
= target_info;
/* And store in baton to allow using it from notify_merge_begin() */
merge_b->notify_begin.nodes_with_mergeinfo = child_with_mergeinfo;
merge_b->children_with_mergeinfo = child_with_mergeinfo;
}
while (ranges_to_merge->nelts > 0)
@ -7648,19 +7697,10 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
do a text-n-props merge; otherwise, do a delete-n-add merge. */
if (! (merge_b->diff_ignore_ancestry || sources_related))
{
struct merge_dir_baton_t dir_baton;
void *dir_baton = open_dir_for_replace_single_file(iterpool);
void *file_baton;
svn_boolean_t skip;
/* Initialize minimal dir baton to allow calculating 'R'eplace
from 'D'elete + 'A'dd. */
memset(&dir_baton, 0, sizeof(dir_baton));
dir_baton.pool = iterpool;
dir_baton.tree_conflict_reason = CONFLICT_REASON_NONE;
dir_baton.tree_conflict_action = svn_wc_conflict_action_edit;
dir_baton.skip_reason = svn_wc_notify_state_unknown;
/* Delete... */
file_baton = NULL;
skip = FALSE;
@ -7668,7 +7708,7 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
left_source,
NULL /* right_source */,
NULL /* copyfrom_source */,
&dir_baton,
dir_baton,
processor,
iterpool, iterpool));
if (! skip)
@ -7687,7 +7727,7 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
NULL /* left_source */,
right_source,
NULL /* copyfrom_source */,
&dir_baton,
dir_baton,
processor,
iterpool, iterpool));
if (! skip)
@ -7758,7 +7798,7 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
(This list is used from notify_merge_begin)
Directory merges use remove_first_range_from_remaining_ranges() */
svn_sort__array_delete(ranges_to_merge, 0, 1);
SVN_ERR(svn_sort__array_delete2(ranges_to_merge, 0, 1));
}
merge_b->notify_begin.last_abspath = NULL;
} /* !merge_b->record_only */
@ -7819,7 +7859,7 @@ do_file_merge(svn_mergeinfo_catalog_t result_catalog,
}
}
merge_b->notify_begin.nodes_with_mergeinfo = NULL;
merge_b->children_with_mergeinfo = NULL;
svn_pool_destroy(iterpool);
@ -7878,7 +7918,7 @@ process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b,
was added (with preexisting mergeinfo) by the merge. That's actually
more correct, since the inherited mergeinfo likely describes
non-existent or unrelated merge history, but it's not quite so simple
as that, see http://subversion.tigris.org/issues/show_bug.cgi?id=4309
as that, see https://issues.apache.org/jira/browse/SVN-4309
*/
/* Get the path's new explicit mergeinfo... */
@ -7945,7 +7985,8 @@ process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b,
/* Set the path's remaining_ranges equal to its parent's. */
new_child->remaining_ranges = svn_rangelist_dup(
parent->remaining_ranges, pool);
insert_child_to_merge(children_with_mergeinfo, new_child, pool);
SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
new_child, pool));
}
}
}
@ -8269,7 +8310,7 @@ flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
merge_b->target->abspath, depth, merge_b->ctx->wc_ctx,
merge_b->ra_session1, scratch_pool, iterpool));
/* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
/* Issue #4056: Walk CHILDREN_WITH_MERGEINFO reverse depth-first
order. This way each child knows if it has operative missing/switched
children which necessitates non-inheritable mergeinfo. */
for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--)
@ -8432,7 +8473,7 @@ flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
}
else /* child->record_mergeinfo */
{
/* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
/* If CHILD is in CHILDREN_WITH_MERGEINFO simply
because it had no explicit mergeinfo of its own at the
start of the merge but is the child of of some path with
non-inheritable mergeinfo, then the explicit mergeinfo it
@ -8457,7 +8498,7 @@ flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described
by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment
by CHILDREN_WITH_MERGEINFO -- see the global comment
'THE CHILDREN_WITH_MERGEINFO ARRAY'. Obviously this should only
be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO().
@ -8508,10 +8549,10 @@ record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog,
range.inheritable = TRUE;
/* Remove absent children at or under MERGE_B->target->abspath from
NOTIFY_B->CHILDREN_WITH_MERGEINFO
CHILDREN_WITH_MERGEINFO
before we calculate the merges performed. */
remove_absent_children(merge_b->target->abspath,
children_with_mergeinfo);
SVN_ERR(remove_absent_children(merge_b->target->abspath,
children_with_mergeinfo));
/* Determine which subtrees of interest need mergeinfo recorded... */
SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
@ -9334,7 +9375,7 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
/* Point our RA_SESSION to the URL of our youngest merge source side. */
ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2;
/* Fill NOTIFY_B->CHILDREN_WITH_MERGEINFO with child paths (const
/* Fill CHILDREN_WITH_MERGEINFO with child paths (const
svn_client__merge_path_t *) which might have intersecting merges
because they meet one or more of the criteria described in
get_mergeinfo_paths(). Here the paths are arranged in a depth
@ -9344,13 +9385,13 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
merge_b->dry_run, merge_b->same_repos,
merge_b->ctx, scratch_pool, scratch_pool));
/* The first item from the NOTIFY_B->CHILDREN_WITH_MERGEINFO is always
/* The first item from the CHILDREN_WITH_MERGEINFO is always
the target thanks to depth-first ordering. */
target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0,
svn_client__merge_path_t *);
/* If we are honoring mergeinfo, then for each item in
NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
merged, and then merge it. Otherwise, we just merge what we were asked
to merge across the whole tree. */
SVN_ERR(populate_remaining_ranges(children_with_mergeinfo,
@ -9370,7 +9411,7 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
/* The merge target TARGET_ABSPATH and/or its subtrees may not need all
of SOURCE->rev1:rev2 applied. So examine
NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting
CHILDREN_WITH_MERGEINFO to find the oldest starting
revision that actually needs to be merged (for reverse merges this is
the youngest starting revision).
@ -9408,7 +9449,7 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
/* Is there anything to merge? */
if (SVN_IS_VALID_REVNUM(start_rev))
{
/* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest
/* Now examine CHILDREN_WITH_MERGEINFO to find the oldest
ending revision that actually needs to be merged (for reverse
merges this is the youngest ending revision). */
svn_revnum_t end_rev =
@ -9417,7 +9458,7 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
/* While END_REV is valid, do the following:
1. Tweak each NOTIFY_B->CHILDREN_WITH_MERGEINFO element so that
1. Tweak each CHILDREN_WITH_MERGEINFO element so that
the element's remaining_ranges member has as its first element
a range that ends with end_rev.
@ -9425,17 +9466,17 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
on MERGE_B->target->abspath for start_rev:end_rev.
3. Remove the first element from each
NOTIFY_B->CHILDREN_WITH_MERGEINFO element's remaining_ranges
CHILDREN_WITH_MERGEINFO element's remaining_ranges
member.
4. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
4. Again examine CHILDREN_WITH_MERGEINFO to find the most
inclusive starting revision that actually needs to be merged and
update start_rev. This prevents us from needlessly contacting the
repository and doing a diff where we describe the entire target
tree as *not* needing any of the requested range. This can happen
whenever we have mergeinfo with gaps in it for the merge source.
5. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
5. Again examine CHILDREN_WITH_MERGEINFO to find the most
inclusive ending revision that actually needs to be merged and
update end_rev.
@ -9477,8 +9518,9 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
svn_pool_clear(iterpool);
slice_remaining_ranges(children_with_mergeinfo,
is_rollback, end_rev, scratch_pool);
SVN_ERR(slice_remaining_ranges(children_with_mergeinfo,
is_rollback, end_rev,
scratch_pool));
/* Reset variables that must be reset for every drive */
merge_b->notify_begin.last_abspath = NULL;
@ -9496,23 +9538,23 @@ do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
/* If any paths picked up explicit mergeinfo as a result of
the merge we need to make sure any mergeinfo those paths
inherited is recorded and then add these paths to
NOTIFY_B->CHILDREN_WITH_MERGEINFO.*/
CHILDREN_WITH_MERGEINFO.*/
SVN_ERR(process_children_with_new_mergeinfo(
merge_b, children_with_mergeinfo,
scratch_pool));
/* If any subtrees had their explicit mergeinfo deleted as a
result of the merge then remove these paths from
NOTIFY_B->CHILDREN_WITH_MERGEINFO since there is no need
CHILDREN_WITH_MERGEINFO since there is no need
to consider these subtrees for subsequent editor drives
nor do we want to record mergeinfo on them describing
the merge itself. */
remove_children_with_deleted_mergeinfo(
merge_b, children_with_mergeinfo);
SVN_ERR(remove_children_with_deleted_mergeinfo(
merge_b, children_with_mergeinfo));
/* Prepare for the next iteration (if any). */
remove_first_range_from_remaining_ranges(
end_rev, children_with_mergeinfo, scratch_pool);
SVN_ERR(remove_first_range_from_remaining_ranges(
end_rev, children_with_mergeinfo, scratch_pool));
/* If we raised any conflicts, break out and report how much
we have merged. */
@ -9634,7 +9676,7 @@ do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *));
/* And make it read-only accessible from the baton */
merge_b->notify_begin.nodes_with_mergeinfo = children_with_mergeinfo;
merge_b->children_with_mergeinfo = children_with_mergeinfo;
/* If we are not honoring mergeinfo we can skip right to the
business of merging changes! */
@ -9652,7 +9694,7 @@ do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
processor, depth,
merge_b, result_pool, scratch_pool));
merge_b->notify_begin.nodes_with_mergeinfo = NULL;
merge_b->children_with_mergeinfo = NULL;
return SVN_NO_ERROR;
}
@ -9889,28 +9931,13 @@ do_merge(apr_hash_t **modified_subtrees,
merge_cmd_baton.added_abspaths = apr_hash_make(result_pool);
merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool);
{
svn_diff_tree_processor_t *merge_processor;
merge_cmd_baton.notify_func = notify_merging;
merge_cmd_baton.notify_baton = &merge_cmd_baton.notify_begin;
merge_cmd_baton.notify_begin.merge_b = &merge_cmd_baton;
merge_cmd_baton.notify_begin.notify_func2 = ctx->notify_func2;
merge_cmd_baton.notify_begin.notify_baton2 = ctx->notify_baton2;
merge_processor = svn_diff__tree_processor_create(&merge_cmd_baton,
scratch_pool);
merge_processor->dir_opened = merge_dir_opened;
merge_processor->dir_changed = merge_dir_changed;
merge_processor->dir_added = merge_dir_added;
merge_processor->dir_deleted = merge_dir_deleted;
merge_processor->dir_closed = merge_dir_closed;
merge_processor->file_opened = merge_file_opened;
merge_processor->file_changed = merge_file_changed;
merge_processor->file_added = merge_file_added;
merge_processor->file_deleted = merge_file_deleted;
/* Not interested in file_closed() */
merge_processor->node_absent = merge_node_absent;
processor = merge_processor;
}
processor = merge_apply_processor(&merge_cmd_baton, scratch_pool);
if (src_session)
{

View File

@ -604,7 +604,7 @@ mtcc_op_contains_non_delete(const mtcc_op_t *op)
static svn_error_t *
mtcc_add_delete(const char *relpath,
svn_boolean_t for_move,
svn_client__mtcc_t *mtcc,
svn_client__mtcc_t *mtcc,
apr_pool_t *scratch_pool)
{
mtcc_op_t *op;
@ -636,7 +636,7 @@ mtcc_add_delete(const char *relpath,
{
/* Allow deleting directories, that are unmodified except for
one or more deleted descendants */
SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, TRUE,
FALSE, FALSE, mtcc->pool, scratch_pool));

View File

@ -343,7 +343,9 @@ strip_path(const char **result, const char *path, int strip_count,
components = svn_path_decompose(path, scratch_pool);
if (strip_count > components->nelts)
return svn_error_createf(SVN_ERR_CLIENT_PATCH_BAD_STRIP_COUNT, NULL,
_("Cannot strip %u components from '%s'"),
Q_("Cannot strip %u component from '%s'",
"Cannot strip %u components from '%s'",
strip_count),
strip_count,
svn_dirent_local_style(path, scratch_pool));
@ -1018,6 +1020,7 @@ init_patch_target(patch_target_t **patch_target,
target_content_t *content;
svn_boolean_t has_text_changes = FALSE;
svn_boolean_t follow_moves;
const char *tempdir_abspath;
has_text_changes = ((patch->hunks && patch->hunks->nelts > 0)
|| patch->binary_patch);
@ -1223,8 +1226,10 @@ init_patch_target(patch_target_t **patch_target,
}
/* Open a temporary file to write the patched result to. */
SVN_ERR(svn_wc__get_tmpdir(&tempdir_abspath, wc_ctx,
target->local_abspath, scratch_pool, scratch_pool));
SVN_ERR(svn_io_open_unique_file3(&target->patched_file,
&target->patched_path, NULL,
&target->patched_path, tempdir_abspath,
remove_tempfiles ?
svn_io_file_del_on_pool_cleanup :
svn_io_file_del_none,
@ -1236,7 +1241,7 @@ init_patch_target(patch_target_t **patch_target,
/* Open a temporary stream to write rejected hunks to. */
SVN_ERR(svn_stream_open_unique(&target->reject_stream,
&target->reject_path, NULL,
&target->reject_path, tempdir_abspath,
remove_tempfiles ?
svn_io_file_del_on_pool_cleanup :
svn_io_file_del_none,
@ -2145,8 +2150,8 @@ reject_hunk(patch_target_t *target, target_content_t *content,
if (prop_name)
{
/* ### Print 'Added', 'Deleted' or 'Modified' instead of 'Property'. */
svn_stream_printf(target->reject_stream,
pool, "Property: %s" APR_EOL_STR, prop_name);
SVN_ERR(svn_stream_printf(target->reject_stream,
pool, "Property: %s" APR_EOL_STR, prop_name));
atat = prop_atat;
}
else

View File

@ -402,8 +402,7 @@ svn_client__open_ra_session_internal(svn_ra_session_t **ra_session,
}
}
/* If the caller allows for auto-following redirections, and the
RA->open() call above reveals a CORRECTED_URL, try the new URL.
/* If the caller allows for auto-following redirections, try the new URL.
We'll do this in a loop up to some maximum number follow-and-retry
attempts. */
if (corrected_url)
@ -414,12 +413,14 @@ svn_client__open_ra_session_internal(svn_ra_session_t **ra_session,
*corrected_url = NULL;
while (attempts_left--)
{
const char *corrected = NULL;
const char *corrected = NULL; /* canonicalized version */
const char *redirect_url = NULL; /* non-canonicalized version */
/* Try to open the RA session. If this is our last attempt,
don't accept corrected URLs from the RA provider. */
SVN_ERR(svn_ra_open4(ra_session,
SVN_ERR(svn_ra_open5(ra_session,
attempts_left == 0 ? NULL : &corrected,
attempts_left == 0 ? NULL : &redirect_url,
base_url, uuid, cbtable, cb, ctx->config,
result_pool));
@ -441,19 +442,28 @@ svn_client__open_ra_session_internal(svn_ra_session_t **ra_session,
*corrected_url = corrected;
/* Make sure we've not attempted this URL before. */
if (svn_hash_gets(attempted, corrected))
if (svn_hash_gets(attempted, redirect_url))
return svn_error_createf(SVN_ERR_CLIENT_CYCLE_DETECTED, NULL,
_("Redirect cycle detected for URL '%s'"),
corrected);
redirect_url);
/*
* Remember this redirect URL so we don't wind up in a loop.
*
* Store the non-canonicalized version of the URL. The canonicalized
* version is insufficient for loop detection because we might not get
* an exact match against URLs used by the RA protocol-layer (the URL
* used by the protocol may contain trailing slashes, for example,
* which are stripped during canonicalization).
*/
svn_hash_sets(attempted, redirect_url, (void *)1);
/* Remember this CORRECTED_URL so we don't wind up in a loop. */
svn_hash_sets(attempted, corrected, (void *)1);
base_url = corrected;
}
}
else
{
SVN_ERR(svn_ra_open4(ra_session, NULL, base_url,
SVN_ERR(svn_ra_open5(ra_session, NULL, NULL, base_url,
uuid, cbtable, cb, ctx->config, result_pool));
}

View File

@ -51,6 +51,7 @@
#include "private/svn_subr_private.h"
#include "private/svn_wc_private.h"
#include "private/svn_editor.h"
#include "private/svn_sorts_private.h"
/* Overall crawler editor baton. */
struct edit_baton {
@ -380,10 +381,10 @@ get_file_from_ra(struct file_baton *fb,
way. Hence this little hack: We populate FILE_BATON->PROPCHANGES only
with *actual* property changes.
See http://subversion.tigris.org/issues/show_bug.cgi?id=3657#desc9 and
See https://issues.apache.org/jira/browse/SVN-3657#desc9 and
http://svn.haxx.se/dev/archive-2010-08/0351.shtml for more details.
*/
static void
static svn_error_t *
remove_non_prop_changes(apr_hash_t *pristine_props,
apr_array_header_t *changes)
{
@ -391,7 +392,7 @@ remove_non_prop_changes(apr_hash_t *pristine_props,
/* For added nodes, there is nothing to filter. */
if (apr_hash_count(pristine_props) == 0)
return;
return SVN_NO_ERROR;
for (i = 0; i < changes->nelts; i++)
{
@ -404,18 +405,13 @@ remove_non_prop_changes(apr_hash_t *pristine_props,
if (old_val && svn_string_compare(old_val, change->value))
{
int j;
/* Remove the matching change by shifting the rest */
for (j = i; j < changes->nelts - 1; j++)
{
APR_ARRAY_IDX(changes, j, svn_prop_t)
= APR_ARRAY_IDX(changes, j+1, svn_prop_t);
}
changes->nelts--;
/* Remove the matching change and re-check the current index */
SVN_ERR(svn_sort__array_delete2(changes, i, 1));
i--;
}
}
}
return SVN_NO_ERROR;
}
/* Get the empty file associated with the edit baton. This is cached so
@ -1015,7 +1011,7 @@ close_file(void *file_baton,
}
if (fb->pristine_props)
remove_non_prop_changes(fb->pristine_props, fb->propchanges);
SVN_ERR(remove_non_prop_changes(fb->pristine_props, fb->propchanges));
right_props = svn_prop__patch(fb->pristine_props, fb->propchanges,
fb->pool);
@ -1088,7 +1084,7 @@ close_directory(void *dir_baton,
if (db->propchanges->nelts > 0)
{
remove_non_prop_changes(pristine_props, db->propchanges);
SVN_ERR(remove_non_prop_changes(pristine_props, db->propchanges));
}
if (db->propchanges->nelts > 0 || db->added)

View File

@ -51,42 +51,32 @@ struct revert_with_write_lock_baton {
const apr_array_header_t *changelists;
svn_boolean_t clear_changelists;
svn_boolean_t metadata_only;
svn_boolean_t added_keep_local;
svn_client_ctx_t *ctx;
};
/* (Note: All arguments are in the baton above.)
Attempt to revert LOCAL_ABSPATH.
Attempt to revert LOCAL_ABSPATH by calling svn_wc_revert6(), which
see for further details.
If DEPTH is svn_depth_empty, revert just the properties on the
directory; else if svn_depth_files, revert the properties and any
files immediately under the directory; else if
svn_depth_immediates, revert all of the preceding plus properties
on immediate subdirectories; else if svn_depth_infinity, revert
path and everything under it fully recursively.
CHANGELISTS is an array of const char * changelist names, used as a
restrictive filter on items reverted; that is, don't revert any
item unless it's a member of one of those changelists. If
CHANGELISTS is empty (or altogether NULL), no changelist filtering occurs.
Consult CTX to determine whether or not to revert timestamp to the
time of last commit ('use-commit-times = yes').
If PATH is unversioned, return SVN_ERR_UNVERSIONED_RESOURCE. */
If the target isn't versioned, send a 'skip' notification and return
no error.
*/
static svn_error_t *
revert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
struct revert_with_write_lock_baton *b = baton;
svn_error_t *err;
err = svn_wc_revert5(b->ctx->wc_ctx,
err = svn_wc_revert6(b->ctx->wc_ctx,
b->local_abspath,
b->depth,
b->use_commit_times,
b->changelists,
b->clear_changelists,
b->metadata_only,
b->added_keep_local,
b->ctx->cancel_func, b->ctx->cancel_baton,
b->ctx->notify_func2, b->ctx->notify_baton2,
scratch_pool);
@ -123,11 +113,12 @@ revert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
svn_error_t *
svn_client_revert3(const apr_array_header_t *paths,
svn_client_revert4(const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_boolean_t clear_changelists,
svn_boolean_t metadata_only,
svn_boolean_t added_keep_local,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@ -183,6 +174,7 @@ svn_client_revert3(const apr_array_header_t *paths,
baton.changelists = changelists;
baton.clear_changelists = clear_changelists;
baton.metadata_only = metadata_only;
baton.added_keep_local = added_keep_local;
baton.ctx = ctx;
err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool);

View File

@ -146,7 +146,14 @@ svn_client__get_revision_number(svn_revnum_t *revnum,
scratch_pool));
if (revision->kind == svn_opt_revision_previous)
(*revnum)--;
{
if (*revnum == 0)
return svn_error_createf(
SVN_ERR_CLIENT_BAD_REVISION, NULL,
_("Path '%s' has no previous revision"),
svn_dirent_local_style(local_abspath, scratch_pool));
--(*revnum);
}
}
break;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,552 +0,0 @@
/*
* shelve.c: implementation of the 'shelve' commands
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
/* ==================================================================== */
/* We define this here to remove any further warnings about the usage of
experimental functions in this file. */
#define SVN_EXPERIMENTAL
#include "svn_client.h"
#include "svn_wc.h"
#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
#include "svn_utf.h"
#include "svn_ctype.h"
#include "client.h"
#include "private/svn_client_private.h"
#include "private/svn_wc_private.h"
#include "svn_private_config.h"
static svn_error_t *
shelf_name_encode(char **encoded_name_p,
const char *name,
apr_pool_t *result_pool)
{
char *encoded_name
= apr_palloc(result_pool, strlen(name) * 2 + 1);
char *out_pos = encoded_name;
if (name[0] == '\0')
return svn_error_create(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
_("Shelf name cannot be the empty string"));
while (*name)
{
apr_snprintf(out_pos, 3, "%02x", (unsigned char)(*name++));
out_pos += 2;
}
*encoded_name_p = encoded_name;
return SVN_NO_ERROR;
}
static svn_error_t *
shelf_name_decode(char **decoded_name_p,
const char *codename,
apr_pool_t *result_pool)
{
svn_stringbuf_t *sb
= svn_stringbuf_create_ensure(strlen(codename) / 2, result_pool);
const char *input = codename;
while (*input)
{
int c;
int nchars;
int nitems = sscanf(input, "%02x%n", &c, &nchars);
if (nitems != 1 || nchars != 2)
return svn_error_createf(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
_("Shelve: Bad encoded name '%s'"), codename);
svn_stringbuf_appendbyte(sb, c);
input += 2;
}
*decoded_name_p = sb->data;
return SVN_NO_ERROR;
}
/* Set *NAME to the shelf name from FILENAME. */
static svn_error_t *
shelf_name_from_filename(char **name,
const char *filename,
apr_pool_t *result_pool)
{
size_t len = strlen(filename);
if (len > 6 && strcmp(filename + len - 6, ".patch") == 0)
{
char *codename = apr_pstrndup(result_pool, filename, len - 6);
SVN_ERR(shelf_name_decode(name, codename, result_pool));
}
return SVN_NO_ERROR;
}
/* Set *PATCH_ABSPATH to the abspath of the patch file for shelved change
* NAME, no matter whether it exists.
*/
static svn_error_t *
get_patch_abspath(char **patch_abspath,
const char *name,
const char *wc_root_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
char *dir;
char *filename;
SVN_ERR(svn_wc__get_shelves_dir(&dir, ctx->wc_ctx, wc_root_abspath,
scratch_pool, scratch_pool));
SVN_ERR(shelf_name_encode(&filename, name, scratch_pool));
filename = apr_pstrcat(scratch_pool, filename, ".patch", SVN_VA_NULL);
*patch_abspath = svn_dirent_join(dir, filename, result_pool);
return SVN_NO_ERROR;
}
/** Write local changes to a patch file for shelved change @a name.
*
* @a message: An optional log message.
*
* @a wc_root_abspath: The WC root dir.
*
* @a overwrite_existing: If a file at @a patch_abspath exists, overwrite it.
*
* @a paths, @a depth, @a changelists: The selection of local paths to diff.
*/
static svn_error_t *
shelf_write_patch(const char *name,
const char *message,
const char *wc_root_abspath,
svn_boolean_t overwrite_existing,
const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
char *patch_abspath;
apr_int32_t flag;
apr_file_t *outfile;
svn_stream_t *outstream;
svn_stream_t *errstream;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
svn_opt_revision_t peg_revision = {svn_opt_revision_unspecified, {0}};
svn_opt_revision_t start_revision = {svn_opt_revision_base, {0}};
svn_opt_revision_t end_revision = {svn_opt_revision_working, {0}};
SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
ctx, scratch_pool, scratch_pool));
/* Get streams for the output and any error output of the diff. */
/* ### svn_stream_open_writable() doesn't work here: the buffering
goes wrong so that diff headers appear after their hunks.
For now, fix by opening the file without APR_BUFFERED. */
flag = APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE;
if (! overwrite_existing)
flag |= APR_FOPEN_EXCL;
SVN_ERR(svn_io_file_open(&outfile, patch_abspath,
flag, APR_FPROT_OS_DEFAULT, scratch_pool));
outstream = svn_stream_from_aprfile2(outfile, FALSE /*disown*/, scratch_pool);
SVN_ERR(svn_stream_for_stderr(&errstream, scratch_pool));
/* Write the patch file header (log message, etc.) */
if (message)
{
SVN_ERR(svn_stream_printf(outstream, scratch_pool, "%s\n",
message));
}
SVN_ERR(svn_stream_printf(outstream, scratch_pool,
"--This line, and those below, will be ignored--\n\n"));
SVN_ERR(svn_stream_printf(outstream, scratch_pool,
"--This patch was generated by 'svn shelve'--\n\n"));
for (i = 0; i < paths->nelts; i++)
{
const char *path = APR_ARRAY_IDX(paths, i, const char *);
if (svn_path_is_url(path))
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("'%s' is not a local path"), path);
SVN_ERR(svn_dirent_get_absolute(&path, path, scratch_pool));
SVN_ERR(svn_client_diff_peg6(
NULL /*options*/,
path,
&peg_revision,
&start_revision,
&end_revision,
wc_root_abspath,
depth,
TRUE /*notice_ancestry*/,
FALSE /*no_diff_added*/,
FALSE /*no_diff_deleted*/,
TRUE /*show_copies_as_adds*/,
FALSE /*ignore_content_type: FALSE -> omit binary files*/,
FALSE /*ignore_properties*/,
FALSE /*properties_only*/,
FALSE /*use_git_diff_format*/,
SVN_APR_LOCALE_CHARSET,
outstream,
errstream,
changelists,
ctx, iterpool));
}
SVN_ERR(svn_stream_close(outstream));
SVN_ERR(svn_stream_close(errstream));
return SVN_NO_ERROR;
}
/** Apply the patch file for shelved change @a name to the WC.
*
* @a wc_root_abspath: The WC root dir.
*
* @a reverse: Apply the patch in reverse.
*
* @a dry_run: Don't really apply the changes, just notify what would be done.
*/
static svn_error_t *
shelf_apply_patch(const char *name,
const char *wc_root_abspath,
svn_boolean_t reverse,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
char *patch_abspath;
SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
ctx, scratch_pool, scratch_pool));
SVN_ERR(svn_client_patch(patch_abspath, wc_root_abspath,
dry_run, 0 /*strip*/,
reverse,
FALSE /*ignore_whitespace*/,
TRUE /*remove_tempfiles*/, NULL, NULL,
ctx, scratch_pool));
return SVN_NO_ERROR;
}
/** Delete the patch file for shelved change @a name.
*
* @a wc_root_abspath: The WC root dir.
*/
static svn_error_t *
shelf_delete_patch(const char *name,
const char *wc_root_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
char *patch_abspath, *to_abspath;
SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
ctx, scratch_pool, scratch_pool));
to_abspath = apr_pstrcat(scratch_pool, patch_abspath, ".bak", SVN_VA_NULL);
/* remove any previous backup */
SVN_ERR(svn_io_remove_file2(to_abspath, TRUE /*ignore_enoent*/,
scratch_pool));
/* move the patch to a backup file */
SVN_ERR(svn_io_file_rename2(patch_abspath, to_abspath, FALSE /*flush_to_disk*/,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelve(const char *name,
const apr_array_header_t *paths,
svn_depth_t depth,
const apr_array_header_t *changelists,
svn_boolean_t keep_local,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *local_abspath;
const char *wc_root_abspath;
const char *message = "";
svn_error_t *err;
/* ### TODO: check all paths are in same WC; for now use first path */
SVN_ERR(svn_dirent_get_absolute(&local_abspath,
APR_ARRAY_IDX(paths, 0, char *), pool));
SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
local_abspath, ctx, pool, pool));
/* Fetch the log message and any other revprops */
if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
{
const char *tmp_file;
apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(void *));
SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items,
ctx, pool));
if (! message)
return SVN_NO_ERROR;
}
err = shelf_write_patch(name, message, wc_root_abspath,
FALSE /*overwrite_existing*/,
paths, depth, changelists,
ctx, pool);
if (err && APR_STATUS_IS_EEXIST(err->apr_err))
{
return svn_error_quick_wrapf(err,
"Shelved change '%s' already exists",
name);
}
else
SVN_ERR(err);
if (!keep_local)
{
/* Reverse-apply the patch. This should be a safer way to remove those
changes from the WC than running a 'revert' operation. */
SVN_ERR(shelf_apply_patch(name, wc_root_abspath,
TRUE /*reverse*/, dry_run,
ctx, pool));
}
if (dry_run)
{
SVN_ERR(shelf_delete_patch(name, wc_root_abspath,
ctx, pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_unshelve(const char *name,
const char *local_abspath,
svn_boolean_t keep,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *wc_root_abspath;
svn_error_t *err;
SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
local_abspath, ctx, pool, pool));
/* Apply the patch. */
err = shelf_apply_patch(name, wc_root_abspath,
FALSE /*reverse*/, dry_run,
ctx, pool);
if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
{
return svn_error_quick_wrapf(err,
"Shelved change '%s' not found",
name);
}
else
SVN_ERR(err);
/* Remove the patch. */
if (! keep && ! dry_run)
{
SVN_ERR(shelf_delete_patch(name, wc_root_abspath,
ctx, pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelves_delete(const char *name,
const char *local_abspath,
svn_boolean_t dry_run,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *wc_root_abspath;
SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
local_abspath, ctx, pool, pool));
/* Remove the patch. */
if (! dry_run)
{
svn_error_t *err;
err = shelf_delete_patch(name, wc_root_abspath,
ctx, pool);
if (err && APR_STATUS_IS_ENOENT(err->apr_err))
{
return svn_error_quick_wrapf(err,
"Shelved change '%s' not found",
name);
}
else
SVN_ERR(err);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelf_get_paths(apr_hash_t **affected_paths,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *wc_root_abspath;
char *patch_abspath;
svn_patch_file_t *patch_file;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_t *paths = apr_hash_make(result_pool);
SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
local_abspath, ctx, scratch_pool, scratch_pool));
SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
ctx, scratch_pool, scratch_pool));
SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, result_pool));
while (1)
{
svn_patch_t *patch;
svn_pool_clear(iterpool);
SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
FALSE /*reverse*/,
FALSE /*ignore_whitespace*/,
iterpool, iterpool));
if (! patch)
break;
svn_hash_sets(paths,
apr_pstrdup(result_pool, patch->old_filename),
apr_pstrdup(result_pool, patch->new_filename));
}
SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool));
svn_pool_destroy(iterpool);
*affected_paths = paths;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelf_has_changes(svn_boolean_t *has_changes,
const char *name,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
apr_hash_t *patch_paths;
SVN_ERR(svn_client_shelf_get_paths(&patch_paths, name, local_abspath,
ctx, scratch_pool, scratch_pool));
*has_changes = (apr_hash_count(patch_paths) != 0);
return SVN_NO_ERROR;
}
/* Set *LOGMSG to the log message stored in the file PATCH_ABSPATH.
*
* ### Currently just reads the first line.
*/
static svn_error_t *
read_logmsg_from_patch(const char **logmsg,
const char *patch_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_file_t *file;
svn_stream_t *stream;
svn_boolean_t eof;
svn_stringbuf_t *line;
SVN_ERR(svn_io_file_open(&file, patch_abspath,
APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, scratch_pool));
stream = svn_stream_from_aprfile2(file, FALSE /*disown*/, scratch_pool);
SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
SVN_ERR(svn_stream_close(stream));
*logmsg = line->data;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelves_list(apr_hash_t **shelved_patch_infos,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
char *shelves_dir;
apr_hash_t *dirents;
apr_hash_index_t *hi;
SVN_ERR(svn_wc__get_shelves_dir(&shelves_dir, ctx->wc_ctx, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_io_get_dirents3(&dirents, shelves_dir, FALSE /*only_check_type*/,
result_pool, scratch_pool));
*shelved_patch_infos = apr_hash_make(result_pool);
/* Remove non-shelves */
for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
{
const char *filename = apr_hash_this_key(hi);
svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
char *name = NULL;
svn_error_clear(shelf_name_from_filename(&name, filename, result_pool));
if (name && dirent->kind == svn_node_file)
{
svn_client_shelved_patch_info_t *info
= apr_palloc(result_pool, sizeof(*info));
info->dirent = dirent;
info->mtime = info->dirent->mtime;
info->patch_path
= svn_dirent_join(shelves_dir, filename, result_pool);
SVN_ERR(read_logmsg_from_patch(&info->message, info->patch_path,
result_pool, scratch_pool));
svn_hash_sets(*shelved_patch_infos, name, info);
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_shelves_any(svn_boolean_t *any_shelved,
const char *local_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
apr_hash_t *shelved_patch_infos;
SVN_ERR(svn_client_shelves_list(&shelved_patch_infos, local_abspath,
ctx, scratch_pool, scratch_pool));
*any_shelved = apr_hash_count(shelved_patch_infos) != 0;
return SVN_NO_ERROR;
}

View File

@ -23,6 +23,9 @@
/* ==================================================================== */
/* We define this here to remove any further warnings about the usage of
experimental functions in this file. */
#define SVN_EXPERIMENTAL
/*** Includes. ***/
@ -41,6 +44,7 @@
#include "svn_error.h"
#include "svn_hash.h"
#include "private/svn_client_shelf.h"
#include "private/svn_client_private.h"
#include "private/svn_sorts_private.h"
#include "private/svn_wc_private.h"
@ -329,6 +333,79 @@ do_external_status(svn_client_ctx_t *ctx,
return SVN_NO_ERROR;
}
/* Run status on shelf SHELF_NAME, if it exists.
*/
static svn_error_t *
shelf_status(const char *shelf_name,
const char *target_abspath,
svn_wc_status_func4_t status_func,
void *status_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_client__shelf_t *shelf;
svn_client__shelf_version_t *shelf_version;
const char *wc_relpath;
err = svn_client__shelf_open_existing(&shelf,
shelf_name, target_abspath,
ctx, scratch_pool);
if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
{
svn_error_clear(err);
return SVN_NO_ERROR;
}
else
SVN_ERR(err);
SVN_ERR(svn_client__shelf_version_open(&shelf_version,
shelf, shelf->max_version,
scratch_pool, scratch_pool));
wc_relpath = svn_dirent_skip_ancestor(shelf->wc_root_abspath, target_abspath);
SVN_ERR(svn_client__shelf_version_status_walk(shelf_version, wc_relpath,
status_func, status_baton,
scratch_pool));
SVN_ERR(svn_client__shelf_close(shelf, scratch_pool));
return SVN_NO_ERROR;
}
/* Run status on all shelves named in CHANGELISTS by a changelist name
* of the form "svn:shelf:SHELF_NAME", if they exist.
*/
static svn_error_t *
shelves_status(const apr_array_header_t *changelists,
const char *target_abspath,
svn_wc_status_func4_t status_func,
void *status_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
static const char PREFIX[] = "svn:shelf:";
static const int PREFIX_LEN = 10;
int i;
if (! changelists)
return SVN_NO_ERROR;
for (i = 0; i < changelists->nelts; i++)
{
const char *cl = APR_ARRAY_IDX(changelists, i, const char *);
if (strncmp(cl, PREFIX, PREFIX_LEN) == 0)
{
const char *shelf_name = cl + PREFIX_LEN;
SVN_ERR(shelf_status(shelf_name, target_abspath,
status_func, status_baton,
ctx, scratch_pool));
}
}
return SVN_NO_ERROR;
}
/*** Public Interface. ***/
@ -586,6 +663,9 @@ svn_client_status6(svn_revnum_t *result_rev,
}
else
{
SVN_ERR(shelves_status(changelists, target_abspath,
tweak_status, &sb,
ctx, pool));
err = svn_wc_walk_status(ctx->wc_ctx, target_abspath,
depth, get_all, no_ignore, FALSE, ignores,
tweak_status, &sb,

View File

@ -182,6 +182,88 @@ record_conflict(svn_wc_conflict_result_t **result,
return SVN_NO_ERROR;
}
/* Perform post-update processing of externals defined below LOCAL_ABSPATH. */
static svn_error_t *
handle_externals(svn_boolean_t *timestamp_sleep,
const char *local_abspath,
svn_depth_t depth,
const char *repos_root_url,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
apr_hash_t *new_externals;
apr_hash_t *new_depths;
SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
&new_depths,
ctx->wc_ctx, local_abspath,
depth,
scratch_pool, scratch_pool));
SVN_ERR(svn_client__handle_externals(new_externals,
new_depths,
repos_root_url, local_abspath,
depth, timestamp_sleep, ra_session,
ctx, scratch_pool));
return SVN_NO_ERROR;
}
/* Try to reuse the RA session by reparenting it to the anchor_url.
* This code is probably overly cautious since we only use this
* currently when parents are missing and so all the anchor_urls
* have to be in the same repo.
* Note that ra_session_p is an (optional) input parameter as well
* as an output parameter. */
static svn_error_t *
reuse_ra_session(svn_ra_session_t **ra_session_p,
const char **corrected_url,
const char *anchor_url,
const char *anchor_abspath,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_ra_session_t *ra_session = *ra_session_p;
if (ra_session)
{
svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
{
/* session changed repos, can't reuse it */
svn_error_clear(err);
ra_session = NULL;
}
else
{
return svn_error_trace(err);
}
}
else
{
*corrected_url = NULL;
}
}
/* Open an RA session for the URL if one isn't already available */
if (!ra_session)
{
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, corrected_url,
anchor_url,
anchor_abspath, NULL,
TRUE /* write_dav_props */,
TRUE /* read_dav_props */,
ctx,
result_pool, scratch_pool));
*ra_session_p = ra_session;
}
return SVN_NO_ERROR;
}
/* This is a helper for svn_client__update_internal(), which see for
an explanation of most of these parameters. Some stuff that's
unique is as follows:
@ -320,6 +402,18 @@ update_internal(svn_revnum_t *result_rev,
ctx->notify_func2, ctx->notify_baton2,
scratch_pool));
if (!ignore_externals)
{
/* We may now be able to remove externals below LOCAL_ABSPATH. */
SVN_ERR(reuse_ra_session(ra_session_p, &corrected_url,
anchor_url, anchor_abspath,
ctx, result_pool, scratch_pool));
ra_session = *ra_session_p;
SVN_ERR(handle_externals(timestamp_sleep, local_abspath, depth,
repos_root_url, ra_session, ctx,
scratch_pool));
}
/* Target excluded, we are done now */
return SVN_NO_ERROR;
}
@ -373,44 +467,9 @@ update_internal(svn_revnum_t *result_rev,
ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
}
/* Try to reuse the RA session by reparenting it to the anchor_url.
* This code is probably overly cautious since we only use this
* currently when parents are missing and so all the anchor_urls
* have to be in the same repo. */
if (ra_session)
{
svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
{
/* session changed repos, can't reuse it */
svn_error_clear(err);
ra_session = NULL;
}
else
{
return svn_error_trace(err);
}
}
else
{
corrected_url = NULL;
}
}
/* Open an RA session for the URL if one isn't already available */
if (!ra_session)
{
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
anchor_url,
anchor_abspath, NULL,
TRUE /* write_dav_props */,
TRUE /* read_dav_props */,
ctx,
result_pool, scratch_pool));
*ra_session_p = ra_session;
}
SVN_ERR(reuse_ra_session(ra_session_p, &corrected_url, anchor_url,
anchor_abspath, ctx, result_pool, scratch_pool));
ra_session = *ra_session_p;
/* If we got a corrected URL from the RA subsystem, we'll need to
relocate our working copy first. */
@ -513,19 +572,8 @@ update_internal(svn_revnum_t *result_rev,
if ((SVN_DEPTH_IS_RECURSIVE(depth) || cropping_target)
&& (! ignore_externals))
{
apr_hash_t *new_externals;
apr_hash_t *new_depths;
SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
&new_depths,
ctx->wc_ctx, local_abspath,
depth,
scratch_pool, scratch_pool));
SVN_ERR(svn_client__handle_externals(new_externals,
new_depths,
repos_root_url, local_abspath,
depth, timestamp_sleep, ra_session,
ctx, scratch_pool));
SVN_ERR(handle_externals(timestamp_sleep, local_abspath, depth,
repos_root_url, ra_session, ctx, scratch_pool));
}
/* Let everyone know we're finished here (unless we're asked not to). */
@ -567,7 +615,7 @@ svn_client__update_internal(svn_revnum_t *result_rev,
{
const char *anchor_abspath, *lockroot_abspath;
svn_error_t *err;
svn_opt_revision_t peg_revision = *revision;
svn_opt_revision_t opt_rev = *revision; /* operative revision */
apr_hash_t *conflicted_paths
= ctx->conflict_func2 ? apr_hash_make(pool) : NULL;
@ -620,7 +668,7 @@ svn_client__update_internal(svn_revnum_t *result_rev,
err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
&ra_session, missing_parent,
anchor_abspath, &peg_revision, svn_depth_empty,
anchor_abspath, &opt_rev, svn_depth_empty,
FALSE, ignore_externals,
allow_unver_obstructions, adds_as_modification,
FALSE, ctx, pool, iterpool);
@ -631,8 +679,8 @@ svn_client__update_internal(svn_revnum_t *result_rev,
/* If we successfully updated a missing parent, let's re-use
the returned revision number for future updates for the
sake of consistency. */
peg_revision.kind = svn_opt_revision_number;
peg_revision.value.number = *result_rev;
opt_rev.kind = svn_opt_revision_number;
opt_rev.value.number = *result_rev;
}
svn_pool_destroy(iterpool);
@ -648,7 +696,7 @@ svn_client__update_internal(svn_revnum_t *result_rev,
err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
&ra_session,
local_abspath, anchor_abspath,
&peg_revision, depth, depth_is_sticky,
&opt_rev, depth, depth_is_sticky,
ignore_externals, allow_unver_obstructions,
adds_as_modification,
TRUE, ctx, pool, pool);

View File

@ -303,7 +303,7 @@ upgrade_externals_from_properties(svn_client_ctx_t *ctx,
{
apr_hash_index_t *hi;
apr_pool_t *iterpool;
apr_pool_t *iterpool2;
apr_pool_t *inner_iterpool;
apr_hash_t *externals;
svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
@ -317,7 +317,7 @@ upgrade_externals_from_properties(svn_client_ctx_t *ctx,
scratch_pool, scratch_pool));
iterpool = svn_pool_create(scratch_pool);
iterpool2 = svn_pool_create(scratch_pool);
inner_iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, externals); hi;
hi = apr_hash_next(hi))
@ -351,14 +351,12 @@ upgrade_externals_from_properties(svn_client_ctx_t *ctx,
iterpool, iterpool);
if (!err)
externals_parent_url = svn_path_url_add_component2(
externals_parent_repos_root_url,
externals_parent_repos_relpath,
iterpool);
if (!err)
err = svn_wc_parse_externals_description3(
&externals_p, svn_dirent_dirname(local_abspath, iterpool),
external_desc->data, FALSE, iterpool);
{
err = svn_wc_parse_externals_description3(
&externals_p, svn_dirent_dirname(local_abspath, iterpool),
external_desc->data, FALSE, iterpool);
}
if (err)
{
svn_wc_notify_t *notify =
@ -376,24 +374,29 @@ upgrade_externals_from_properties(svn_client_ctx_t *ctx,
continue;
}
externals_parent_url = svn_path_url_add_component2(
externals_parent_repos_root_url,
externals_parent_repos_relpath,
iterpool);
for (i = 0; i < externals_p->nelts; i++)
{
svn_wc_external_item2_t *item;
item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
svn_pool_clear(iterpool2);
svn_pool_clear(inner_iterpool);
err = upgrade_external_item(ctx, externals_parent_abspath,
externals_parent_url,
externals_parent_repos_root_url,
item, info_baton, iterpool2);
item, info_baton, inner_iterpool);
if (err)
{
svn_wc_notify_t *notify =
svn_wc_create_notify(svn_dirent_join(externals_parent_abspath,
item->target_dir,
iterpool2),
inner_iterpool),
svn_wc_notify_failed_external,
scratch_pool);
notify->err = err;
@ -405,8 +408,8 @@ upgrade_externals_from_properties(svn_client_ctx_t *ctx,
}
}
svn_pool_destroy(inner_iterpool);
svn_pool_destroy(iterpool);
svn_pool_destroy(iterpool2);
return SVN_NO_ERROR;
}

View File

@ -93,6 +93,7 @@ svn_client__pathrev_create_with_session(svn_client__pathrev_t **pathrev_p,
pathrev->rev = rev;
pathrev->url = apr_pstrdup(result_pool, url);
*pathrev_p = pathrev;
SVN_ERR_ASSERT(svn_uri__is_ancestor(pathrev->repos_root_url, url));
return SVN_NO_ERROR;
}

View File

@ -0,0 +1,655 @@
/*
* wc_editor.c: editing the local modifications in the WC.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include <string.h>
#include "svn_hash.h"
#include "svn_client.h"
#include "svn_delta.h"
#include "svn_dirent_uri.h"
#include "svn_error.h"
#include "svn_error_codes.h"
#include "svn_pools.h"
#include "svn_props.h"
#include "svn_wc.h"
#include <apr_md5.h>
#include "client.h"
#include "private/svn_subr_private.h"
#include "private/svn_wc_private.h"
#include "svn_private_config.h"
/* ------------------------------------------------------------------ */
/* WC Modifications Editor.
*
* This editor applies incoming modifications onto the current working state
* of the working copy, to produce a new working state.
*
* Currently, it assumes the working state matches what the edit driver
* expects to find, and may throw an error if not.
*
* For simplicity, we apply incoming edits as they arrive, rather than
* queueing them up to apply in a batch.
*
* TODO:
* - tests
* - use for all existing scenarios ('svn add', 'svn propset', etc.)
* - Instead of 'root_dir_add' option, probably the driver should anchor
* at the parent dir.
* - Instead of 'ignore_mergeinfo' option, implement that as a wrapper.
* - Option to quietly accept changes that seem to be already applied
* in the versioned state and/or on disk.
* Consider 'svn add' which assumes items to be added are found on disk.
* - Notification.
*/
/* Everything we need to know about the edit session.
*/
struct edit_baton_t
{
const char *anchor_abspath;
svn_boolean_t manage_wc_write_lock;
const char *lock_root_abspath; /* the path locked, when locked */
/* True => 'open_root' method will act as 'add_directory' */
svn_boolean_t root_dir_add;
/* True => filter out any incoming svn:mergeinfo property changes */
svn_boolean_t ignore_mergeinfo_changes;
svn_ra_session_t *ra_session;
svn_wc_context_t *wc_ctx;
svn_client_ctx_t *ctx;
svn_wc_notify_func2_t notify_func;
void *notify_baton;
};
/* Everything we need to know about a directory that's open for edits.
*/
struct dir_baton_t
{
apr_pool_t *pool;
struct edit_baton_t *eb;
const char *local_abspath;
};
/* Join PATH onto ANCHOR_ABSPATH.
* Throw an error if the result is outside ANCHOR_ABSPATH.
*/
static svn_error_t *
get_path(const char **local_abspath_p,
const char *anchor_abspath,
const char *path,
apr_pool_t *result_pool)
{
svn_boolean_t under_root;
SVN_ERR(svn_dirent_is_under_root(&under_root, local_abspath_p,
anchor_abspath, path, result_pool));
if (! under_root)
{
return svn_error_createf(
SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("Path '%s' is not in the working copy"),
svn_dirent_local_style(path, result_pool));
}
return SVN_NO_ERROR;
}
/* Create a directory on disk and add it to version control,
* with no properties.
*/
static svn_error_t *
mkdir(const char *abspath,
struct edit_baton_t *eb,
apr_pool_t *scratch_pool)
{
SVN_ERR(svn_io_make_dir_recursively(abspath, scratch_pool));
SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, abspath,
NULL /*properties*/,
TRUE /* skip checks */,
eb->notify_func, eb->notify_baton,
scratch_pool));
return SVN_NO_ERROR;
}
/* Prepare to open or add a directory: initialize a new dir baton.
*
* If PATH is "" and PB is null, it represents the root directory of
* the edit; otherwise PATH is not "" and PB is not null.
*/
static svn_error_t *
dir_open_or_add(struct dir_baton_t **child_dir_baton,
const char *path,
struct dir_baton_t *pb,
struct edit_baton_t *eb,
apr_pool_t *dir_pool)
{
struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db));
db->pool = dir_pool;
db->eb = eb;
SVN_ERR(get_path(&db->local_abspath,
eb->anchor_abspath, path, dir_pool));
*child_dir_baton = db;
return SVN_NO_ERROR;
}
/* */
static svn_error_t *
release_write_lock(struct edit_baton_t *eb,
apr_pool_t *scratch_pool)
{
if (eb->lock_root_abspath)
{
SVN_ERR(svn_wc__release_write_lock(
eb->ctx->wc_ctx, eb->lock_root_abspath, scratch_pool));
eb->lock_root_abspath = NULL;
}
return SVN_NO_ERROR;
}
/* */
static apr_status_t
pool_cleanup_handler(void *root_baton)
{
struct dir_baton_t *db = root_baton;
struct edit_baton_t *eb = db->eb;
svn_error_clear(release_write_lock(eb, db->pool));
return APR_SUCCESS;
}
/* svn_delta_editor_t function */
static svn_error_t *
edit_open(void *edit_baton,
svn_revnum_t base_revision,
apr_pool_t *result_pool,
void **root_baton)
{
struct edit_baton_t *eb = edit_baton;
struct dir_baton_t *db;
SVN_ERR(dir_open_or_add(&db, "", NULL, eb, result_pool));
/* Acquire a WC write lock */
if (eb->manage_wc_write_lock)
{
apr_pool_cleanup_register(db->pool, db,
pool_cleanup_handler,
apr_pool_cleanup_null);
SVN_ERR(svn_wc__acquire_write_lock(&eb->lock_root_abspath,
eb->ctx->wc_ctx,
eb->anchor_abspath,
FALSE /*lock_anchor*/,
db->pool, db->pool));
}
if (eb->root_dir_add)
{
SVN_ERR(mkdir(db->local_abspath, eb, result_pool));
}
*root_baton = db;
return SVN_NO_ERROR;
}
/* svn_delta_editor_t function */
static svn_error_t *
edit_close_or_abort(void *edit_baton,
apr_pool_t *scratch_pool)
{
SVN_ERR(release_write_lock(edit_baton, scratch_pool));
return SVN_NO_ERROR;
}
/* */
static svn_error_t *
delete_entry(const char *path,
svn_revnum_t revision,
void *parent_baton,
apr_pool_t *scratch_pool)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
const char *local_abspath;
SVN_ERR(get_path(&local_abspath,
eb->anchor_abspath, path, scratch_pool));
SVN_ERR(svn_wc_delete4(eb->wc_ctx, local_abspath,
FALSE /*keep_local*/,
TRUE /*delete_unversioned*/,
NULL, NULL, /*cancellation*/
eb->notify_func, eb->notify_baton, scratch_pool));
return SVN_NO_ERROR;
}
/* An svn_delta_editor_t function. */
static svn_error_t *
dir_open(const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *result_pool,
void **child_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
struct dir_baton_t *db;
SVN_ERR(dir_open_or_add(&db, path, pb, eb, result_pool));
*child_baton = db;
return SVN_NO_ERROR;
}
static svn_error_t *
dir_add(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *result_pool,
void **child_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
struct dir_baton_t *db;
/* ### Our caller should be providing a scratch pool */
apr_pool_t *scratch_pool = svn_pool_create(result_pool);
SVN_ERR(dir_open_or_add(&db, path, pb, eb, result_pool));
if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
{
SVN_ERR(svn_client__repos_to_wc_copy_internal(NULL /*timestamp_sleep*/,
svn_node_dir,
copyfrom_path,
copyfrom_revision,
db->local_abspath,
db->eb->ra_session,
db->eb->ctx,
scratch_pool));
}
else
{
SVN_ERR(mkdir(db->local_abspath, eb, result_pool));
}
*child_baton = db;
svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
dir_change_prop(void *dir_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *scratch_pool)
{
struct dir_baton_t *db = dir_baton;
struct edit_baton_t *eb = db->eb;
if (svn_property_kind2(name) != svn_prop_regular_kind
|| (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO)))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value,
svn_depth_empty, FALSE, NULL,
NULL, NULL, /* Cancellation */
NULL, NULL, /* Notification */
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
dir_close(void *dir_baton,
apr_pool_t *scratch_pool)
{
return SVN_NO_ERROR;
}
/* Everything we need to know about a file that's open for edits.
*/
struct file_baton_t
{
apr_pool_t *pool;
struct edit_baton_t *eb;
const char *local_abspath;
/* fields for the transfer of text changes */
const char *writing_file;
unsigned char digest[APR_MD5_DIGESTSIZE]; /* MD5 digest of new fulltext */
svn_stream_t *wc_file_read_stream, *tmp_file_write_stream;
const char *tmp_path;
};
/* Create a new file on disk and add it to version control.
*
* The file is empty and has no properties.
*/
static svn_error_t *
mkfile(const char *abspath,
struct edit_baton_t *eb,
apr_pool_t *scratch_pool)
{
SVN_ERR(svn_io_file_create_empty(abspath, scratch_pool));
SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, abspath,
NULL /*properties*/,
TRUE /* skip checks */,
eb->notify_func, eb->notify_baton,
scratch_pool));
return SVN_NO_ERROR;
}
/* */
static svn_error_t *
file_open_or_add(const char *path,
void *parent_baton,
struct file_baton_t **file_baton,
apr_pool_t *file_pool)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb));
fb->pool = file_pool;
fb->eb = eb;
SVN_ERR(get_path(&fb->local_abspath,
eb->anchor_abspath, path, fb->pool));
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
file_open(const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *result_pool,
void **file_baton)
{
struct file_baton_t *fb;
SVN_ERR(file_open_or_add(path, parent_baton, &fb, result_pool));
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
file_add(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *result_pool,
void **file_baton)
{
struct file_baton_t *fb;
SVN_ERR(file_open_or_add(path, parent_baton, &fb, result_pool));
if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
{
SVN_ERR(svn_client__repos_to_wc_copy_internal(NULL /*timestamp_sleep*/,
svn_node_file,
copyfrom_path,
copyfrom_revision,
fb->local_abspath,
fb->eb->ra_session,
fb->eb->ctx, fb->pool));
}
else
{
SVN_ERR(mkfile(fb->local_abspath, fb->eb, result_pool));
}
*file_baton = fb;
return SVN_NO_ERROR;
}
static svn_error_t *
file_change_prop(void *file_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
struct edit_baton_t *eb = fb->eb;
if (svn_property_kind2(name) != svn_prop_regular_kind
|| (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO)))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value,
svn_depth_empty, FALSE, NULL,
NULL, NULL, /* Cancellation */
NULL, NULL, /* Notification */
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
file_textdelta(void *file_baton,
const char *base_checksum,
apr_pool_t *result_pool,
svn_txdelta_window_handler_t *handler,
void **handler_baton)
{
struct file_baton_t *fb = file_baton;
const char *target_dir = svn_dirent_dirname(fb->local_abspath, fb->pool);
svn_error_t *err;
SVN_ERR_ASSERT(! fb->writing_file);
err = svn_stream_open_readonly(&fb->wc_file_read_stream, fb->local_abspath,
fb->pool, fb->pool);
if (err && APR_STATUS_IS_ENOENT(err->apr_err))
{
svn_error_clear(err);
fb->wc_file_read_stream = svn_stream_empty(fb->pool);
}
else
SVN_ERR(err);
SVN_ERR(svn_stream_open_unique(&fb->tmp_file_write_stream, &fb->writing_file,
target_dir, svn_io_file_del_none,
fb->pool, fb->pool));
svn_txdelta_apply(fb->wc_file_read_stream,
fb->tmp_file_write_stream,
fb->digest,
fb->local_abspath,
fb->pool,
/* Provide the handler directly */
handler, handler_baton);
return SVN_NO_ERROR;
}
static svn_error_t *
file_close(void *file_baton,
const char *text_checksum,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
/* If we have text changes, write them to disk */
if (fb->writing_file)
{
SVN_ERR(svn_stream_close(fb->wc_file_read_stream));
SVN_ERR(svn_io_file_rename2(fb->writing_file, fb->local_abspath,
FALSE /*flush*/, scratch_pool));
}
if (text_checksum)
{
svn_checksum_t *expected_checksum;
svn_checksum_t *actual_checksum;
SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5,
text_checksum, fb->pool));
actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool);
if (! svn_checksum_match(expected_checksum, actual_checksum))
return svn_error_trace(
svn_checksum_mismatch_err(expected_checksum,
actual_checksum,
fb->pool,
_("Checksum mismatch for '%s'"),
svn_dirent_local_style(
fb->local_abspath,
fb->pool)));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__wc_editor_internal(const svn_delta_editor_t **editor_p,
void **edit_baton_p,
const char *dst_abspath,
svn_boolean_t root_dir_add,
svn_boolean_t ignore_mergeinfo_changes,
svn_boolean_t manage_wc_write_lock,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool)
{
svn_delta_editor_t *editor = svn_delta_default_editor(result_pool);
struct edit_baton_t *eb = apr_pcalloc(result_pool, sizeof(*eb));
eb->anchor_abspath = apr_pstrdup(result_pool, dst_abspath);
eb->manage_wc_write_lock = manage_wc_write_lock;
eb->lock_root_abspath = NULL;
eb->root_dir_add = root_dir_add;
eb->ignore_mergeinfo_changes = ignore_mergeinfo_changes;
eb->ra_session = ra_session;
eb->wc_ctx = ctx->wc_ctx;
eb->ctx = ctx;
eb->notify_func = notify_func;
eb->notify_baton = notify_baton;
editor->open_root = edit_open;
editor->close_edit = edit_close_or_abort;
editor->abort_edit = edit_close_or_abort;
editor->delete_entry = delete_entry;
editor->open_directory = dir_open;
editor->add_directory = dir_add;
editor->change_dir_prop = dir_change_prop;
editor->close_directory = dir_close;
editor->open_file = file_open;
editor->add_file = file_add;
editor->change_file_prop = file_change_prop;
editor->apply_textdelta = file_textdelta;
editor->close_file = file_close;
*editor_p = editor;
*edit_baton_p = eb;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__wc_editor(const svn_delta_editor_t **editor_p,
void **edit_baton_p,
const char *dst_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool)
{
SVN_ERR(svn_client__wc_editor_internal(editor_p, edit_baton_p,
dst_abspath,
FALSE /*root_dir_add*/,
FALSE /*ignore_mergeinfo_changes*/,
TRUE /*manage_wc_write_lock*/,
notify_func, notify_baton,
ra_session,
ctx, result_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__wc_copy_mods(const char *src_wc_abspath,
const char *dst_wc_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
svn_client__pathrev_t *base;
const char *dst_wc_url;
svn_ra_session_t *ra_session;
const svn_delta_editor_t *editor;
void *edit_baton;
apr_array_header_t *src_targets = apr_array_make(scratch_pool, 1,
sizeof(char *));
/* We'll need an RA session to obtain the base of any copies */
SVN_ERR(svn_client__wc_node_get_base(&base,
src_wc_abspath, ctx->wc_ctx,
scratch_pool, scratch_pool));
dst_wc_url = base->url;
SVN_ERR(svn_client_open_ra_session2(&ra_session,
dst_wc_url, dst_wc_abspath,
ctx, scratch_pool, scratch_pool));
SVN_ERR(svn_client__wc_editor(&editor, &edit_baton,
dst_wc_abspath,
NULL, NULL, /*notification*/
ra_session, ctx, scratch_pool));
APR_ARRAY_PUSH(src_targets, const char *) = src_wc_abspath;
SVN_ERR(svn_client__wc_replay(src_wc_abspath,
src_targets, svn_depth_infinity, NULL,
editor, edit_baton,
notify_func, notify_baton,
ctx, scratch_pool));
return SVN_NO_ERROR;
}

View File

@ -157,7 +157,7 @@ branch_txn_delete_branch(svn_branch__txn_t *txn,
if (strcmp(b->bid, bid) == 0)
{
svn_sort__array_delete(txn->priv->branches, i, 1);
SVN_ERR(svn_sort__array_delete2(txn->priv->branches, i, 1));
break;
}
}

View File

@ -875,6 +875,8 @@ drive_ev1_props(const char *repos_relpath,
*/
static svn_error_t *
apply_change(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *ev1_relpath,
@ -905,7 +907,7 @@ apply_change(void **dir_baton,
/* Only property edits are allowed on the root. */
SVN_ERR_ASSERT(change->action == RESTRUCTURE_NONE);
SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props,
eb->deditor, *dir_baton, scratch_pool));
editor, *dir_baton, scratch_pool));
/* No further action possible for the root. */
return SVN_NO_ERROR;
@ -913,8 +915,8 @@ apply_change(void **dir_baton,
if (change->action == RESTRUCTURE_DELETE)
{
SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting_rev,
parent_baton, scratch_pool));
SVN_ERR(editor->delete_entry(ev1_relpath, change->deleting_rev,
parent_baton, scratch_pool));
/* No futher action possible for this node. */
return SVN_NO_ERROR;
@ -927,11 +929,11 @@ apply_change(void **dir_baton,
if (change->action == RESTRUCTURE_ADD_ABSENT)
{
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton,
scratch_pool));
else if (change->kind == svn_node_file)
SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton,
SVN_ERR(editor->absent_directory(ev1_relpath, parent_baton,
scratch_pool));
else if (change->kind == svn_node_file)
SVN_ERR(editor->absent_file(ev1_relpath, parent_baton,
scratch_pool));
else
SVN_ERR_MALFUNCTION();
@ -948,8 +950,8 @@ apply_change(void **dir_baton,
/* Do we have an old node to delete first? If so, delete it. */
if (change->deleting)
SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting_rev,
parent_baton, scratch_pool));
SVN_ERR(editor->delete_entry(ev1_relpath, change->deleting_rev,
parent_baton, scratch_pool));
/* If it's a copy, determine the copy source location. */
if (change->copyfrom_path)
@ -974,13 +976,13 @@ apply_change(void **dir_baton,
}
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, dir_baton));
else if (change->kind == svn_node_file)
SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton,
SVN_ERR(editor->add_directory(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, &file_baton));
result_pool, dir_baton));
else if (change->kind == svn_node_file)
SVN_ERR(editor->add_file(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, &file_baton));
else
SVN_ERR_MALFUNCTION();
}
@ -993,13 +995,13 @@ apply_change(void **dir_baton,
when we fetch the base properties.) */
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton,
change->changing_rev,
result_pool, dir_baton));
else if (change->kind == svn_node_file)
SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton,
SVN_ERR(editor->open_directory(ev1_relpath, parent_baton,
change->changing_rev,
result_pool, &file_baton));
result_pool, dir_baton));
else if (change->kind == svn_node_file)
SVN_ERR(editor->open_file(ev1_relpath, parent_baton,
change->changing_rev,
result_pool, &file_baton));
else
SVN_ERR_MALFUNCTION();
}
@ -1007,10 +1009,10 @@ apply_change(void **dir_baton,
/* Apply any properties in CHANGE to the node. */
if (change->kind == svn_node_dir)
SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props,
eb->deditor, *dir_baton, scratch_pool));
editor, *dir_baton, scratch_pool));
else
SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props,
eb->deditor, file_baton, scratch_pool));
editor, file_baton, scratch_pool));
/* Send the text content delta, if new text content is provided. */
if (change->contents_text)
@ -1023,7 +1025,7 @@ apply_change(void **dir_baton,
scratch_pool);
/* ### would be nice to have a BASE_CHECKSUM, but hey: this is the
### shim code... */
SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool,
SVN_ERR(editor->apply_textdelta(file_baton, NULL, scratch_pool,
&handler, &handler_baton));
/* ### it would be nice to send a true txdelta here, but whatever. */
SVN_ERR(svn_txdelta_send_stream(read_stream, handler, handler_baton,
@ -1033,7 +1035,7 @@ apply_change(void **dir_baton,
if (file_baton)
{
SVN_ERR(eb->deditor->close_file(file_baton, NULL, scratch_pool));
SVN_ERR(editor->close_file(file_baton, NULL, scratch_pool));
}
return SVN_NO_ERROR;
@ -1740,7 +1742,7 @@ drive_changes(svn_branch__txn_priv_t *eb,
/* Apply the appropriate Ev1 change to each Ev1-relative path. */
paths = get_unsorted_paths(eb->changes, scratch_pool);
SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton,
SVN_ERR(svn_delta_path_driver3(eb->deditor, eb->dedit_baton,
paths, TRUE /*sort*/,
apply_change, (void *)eb,
scratch_pool));

View File

@ -1577,6 +1577,8 @@ drive_ev1_props(const struct editor_baton *eb,
/* Conforms to svn_delta_path_driver_cb_func_t */
static svn_error_t *
apply_change(void **dir_baton,
const svn_delta_editor_t *deditor,
void *dedit_baton,
void *parent_baton,
void *callback_baton,
const char *ev1_relpath,
@ -1614,8 +1616,8 @@ apply_change(void **dir_baton,
if (change->action == RESTRUCTURE_DELETE)
{
SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
parent_baton, scratch_pool));
SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting,
parent_baton, scratch_pool));
/* No futher action possible for this node. */
return SVN_NO_ERROR;
@ -1627,11 +1629,11 @@ apply_change(void **dir_baton,
if (change->action == RESTRUCTURE_ADD_ABSENT)
{
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton,
scratch_pool));
SVN_ERR(deditor->absent_directory(ev1_relpath, parent_baton,
scratch_pool));
else
SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton,
scratch_pool));
SVN_ERR(deditor->absent_file(ev1_relpath, parent_baton,
scratch_pool));
/* No further action possible for this node. */
return SVN_NO_ERROR;
@ -1645,8 +1647,8 @@ apply_change(void **dir_baton,
/* Do we have an old node to delete first? */
if (SVN_IS_VALID_REVNUM(change->deleting))
SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
parent_baton, scratch_pool));
SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting,
parent_baton, scratch_pool));
/* Are we copying the node from somewhere? */
if (change->copyfrom_path)
@ -1669,24 +1671,24 @@ apply_change(void **dir_baton,
}
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, dir_baton));
SVN_ERR(deditor->add_directory(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, dir_baton));
else
SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, &file_baton));
SVN_ERR(deditor->add_file(ev1_relpath, parent_baton,
copyfrom_url, copyfrom_rev,
result_pool, &file_baton));
}
else
{
if (change->kind == svn_node_dir)
SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton,
change->changing,
result_pool, dir_baton));
SVN_ERR(deditor->open_directory(ev1_relpath, parent_baton,
change->changing,
result_pool, dir_baton));
else
SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton,
change->changing,
result_pool, &file_baton));
SVN_ERR(deditor->open_file(ev1_relpath, parent_baton,
change->changing,
result_pool, &file_baton));
}
/* Apply any properties in CHANGE to the node. */
@ -1703,8 +1705,8 @@ apply_change(void **dir_baton,
/* ### would be nice to have a BASE_CHECKSUM, but hey: this is the
### shim code... */
SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool,
&handler, &handler_baton));
SVN_ERR(deditor->apply_textdelta(file_baton, NULL, scratch_pool,
&handler, &handler_baton));
SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
scratch_pool, scratch_pool));
/* ### it would be nice to send a true txdelta here, but whatever. */
@ -1718,7 +1720,7 @@ apply_change(void **dir_baton,
const char *digest = svn_checksum_to_cstring(change->checksum,
scratch_pool);
SVN_ERR(eb->deditor->close_file(file_baton, digest, scratch_pool));
SVN_ERR(deditor->close_file(file_baton, digest, scratch_pool));
}
return SVN_NO_ERROR;
@ -1747,7 +1749,7 @@ drive_changes(const struct editor_baton *eb,
/* Get a sorted list of Ev1-relative paths. */
paths = get_sorted_paths(eb->changes, eb->base_relpath, scratch_pool);
SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton, paths,
SVN_ERR(svn_delta_path_driver3(eb->deditor, eb->dedit_baton, paths,
FALSE, apply_change, (void *)eb,
scratch_pool));

View File

@ -71,9 +71,11 @@ set_target_revision(void *edit_baton,
SVN_ERR(svn_stream_printf(eb->out, pool, "set_target_revision : %ld\n",
target_revision));
return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
target_revision,
pool);
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
target_revision,
pool));
return SVN_NO_ERROR;
}
static svn_error_t *
@ -90,10 +92,11 @@ open_root(void *edit_baton,
base_revision));
eb->indent_level++;
SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
base_revision,
pool,
&dir_baton->wrapped_dir_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
base_revision,
pool,
&dir_baton->wrapped_dir_baton));
dir_baton->edit_baton = edit_baton;
@ -115,10 +118,12 @@ delete_entry(const char *path,
SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
path, base_revision));
return eb->wrapped_editor->delete_entry(path,
base_revision,
pb->wrapped_dir_baton,
pool);
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->delete_entry(path,
base_revision,
pb->wrapped_dir_baton,
pool));
return SVN_NO_ERROR;
}
static svn_error_t *
@ -139,12 +144,13 @@ add_directory(const char *path,
path, copyfrom_path, copyfrom_revision));
eb->indent_level++;
SVN_ERR(eb->wrapped_editor->add_directory(path,
pb->wrapped_dir_baton,
copyfrom_path,
copyfrom_revision,
pool,
&b->wrapped_dir_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->add_directory(path,
pb->wrapped_dir_baton,
copyfrom_path,
copyfrom_revision,
pool,
&b->wrapped_dir_baton));
b->edit_baton = eb;
*child_baton = b;
@ -168,11 +174,12 @@ open_directory(const char *path,
path, base_revision));
eb->indent_level++;
SVN_ERR(eb->wrapped_editor->open_directory(path,
pb->wrapped_dir_baton,
base_revision,
pool,
&db->wrapped_dir_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->open_directory(path,
pb->wrapped_dir_baton,
base_revision,
pool,
&db->wrapped_dir_baton));
db->edit_baton = eb;
*child_baton = db;
@ -199,12 +206,13 @@ add_file(const char *path,
eb->indent_level++;
SVN_ERR(eb->wrapped_editor->add_file(path,
pb->wrapped_dir_baton,
copyfrom_path,
copyfrom_revision,
pool,
&fb->wrapped_file_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->add_file(path,
pb->wrapped_dir_baton,
copyfrom_path,
copyfrom_revision,
pool,
&fb->wrapped_file_baton));
fb->edit_baton = eb;
*file_baton = fb;
@ -229,11 +237,12 @@ open_file(const char *path,
eb->indent_level++;
SVN_ERR(eb->wrapped_editor->open_file(path,
pb->wrapped_dir_baton,
base_revision,
pool,
&fb->wrapped_file_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->open_file(path,
pb->wrapped_dir_baton,
base_revision,
pool,
&fb->wrapped_file_baton));
fb->edit_baton = eb;
*file_baton = fb;
@ -255,11 +264,38 @@ apply_textdelta(void *file_baton,
SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
base_checksum));
SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
base_checksum,
pool,
handler,
handler_baton));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
base_checksum,
pool,
handler,
handler_baton));
return SVN_NO_ERROR;
}
static svn_error_t *
apply_textdelta_stream(const struct svn_delta_editor_t *editor,
void *file_baton,
const char *base_checksum,
svn_txdelta_stream_open_func_t open_func,
void *open_baton,
apr_pool_t *scratch_pool)
{
struct file_baton *fb = file_baton;
struct edit_baton *eb = fb->edit_baton;
SVN_ERR(write_indent(eb, scratch_pool));
SVN_ERR(svn_stream_printf(eb->out, scratch_pool,
"apply_textdelta_stream : %s\n",
base_checksum));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->apply_textdelta_stream(eb->wrapped_editor,
fb->wrapped_file_baton,
base_checksum,
open_func, open_baton,
scratch_pool));
return SVN_NO_ERROR;
}
@ -278,8 +314,9 @@ close_file(void *file_baton,
SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
text_checksum));
SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
text_checksum, pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
text_checksum, pool));
return SVN_NO_ERROR;
}
@ -295,8 +332,9 @@ absent_file(const char *path,
SVN_ERR(write_indent(eb, pool));
SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
pool));
return SVN_NO_ERROR;
}
@ -312,8 +350,9 @@ close_directory(void *dir_baton,
SVN_ERR(write_indent(eb, pool));
SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
pool));
return SVN_NO_ERROR;
}
@ -330,8 +369,9 @@ absent_directory(const char *path,
SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
path));
SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
pool));
return SVN_NO_ERROR;
}
@ -349,10 +389,11 @@ change_file_prop(void *file_baton,
SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s -> %s\n",
name, value ? value->data : "<deleted>"));
SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
name,
value,
pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
name,
value,
pool));
return SVN_NO_ERROR;
}
@ -370,10 +411,11 @@ change_dir_prop(void *dir_baton,
SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s -> %s\n",
name, value ? value->data : "<deleted>"));
SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
name,
value,
pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
name,
value,
pool));
return SVN_NO_ERROR;
}
@ -387,7 +429,8 @@ close_edit(void *edit_baton,
SVN_ERR(write_indent(eb, pool));
SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
return SVN_NO_ERROR;
}
@ -401,7 +444,8 @@ abort_edit(void *edit_baton,
SVN_ERR(write_indent(eb, pool));
SVN_ERR(svn_stream_printf(eb->out, pool, "abort_edit\n"));
SVN_ERR(eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool));
if (eb->wrapped_editor)
SVN_ERR(eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool));
return SVN_NO_ERROR;
}
@ -414,7 +458,7 @@ svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
const char *prefix,
apr_pool_t *pool)
{
svn_delta_editor_t *tree_editor = apr_palloc(pool, sizeof(*tree_editor));
svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
apr_file_t *errfp;
svn_stream_t *out;
@ -436,6 +480,7 @@ svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
tree_editor->add_file = add_file;
tree_editor->open_file = open_file;
tree_editor->apply_textdelta = apply_textdelta;
tree_editor->apply_textdelta_stream = apply_textdelta_stream;
tree_editor->change_file_prop = change_file_prop;
tree_editor->close_file = close_file;
tree_editor->absent_file = absent_file;

View File

@ -30,6 +30,79 @@
#include "svn_sorts.h"
struct path_driver_2_to_3_baton_t
{
svn_delta_path_driver_cb_func_t callback_func;
void *callback_baton;
svn_boolean_t slash_prefix;
};
/* Convert from a newer to older callback
*/
static svn_error_t *
path_driver_2_to_3_func(void **dir_baton,
const svn_delta_editor_t *editor,
void *edit_baton,
void *parent_baton,
void *callback_baton,
const char *path,
apr_pool_t *pool)
{
struct path_driver_2_to_3_baton_t *b = callback_baton;
if (b->slash_prefix)
path = apr_pstrcat(pool, "/", path, SVN_VA_NULL);
/* Just drop the 'editor' parameters */
SVN_ERR(b->callback_func(dir_baton, parent_baton,
b->callback_baton,
path, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_delta_path_driver2(const svn_delta_editor_t *editor,
void *edit_baton,
const apr_array_header_t *paths,
svn_boolean_t sort_paths,
svn_delta_path_driver_cb_func_t callback_func,
void *callback_baton,
apr_pool_t *pool)
{
struct path_driver_2_to_3_baton_t b;
int i;
b.callback_func = callback_func;
b.callback_baton = callback_baton;
b.slash_prefix = FALSE;
/* Remove any '/' prefix from incoming paths. Arrange to add a '/'
prefix to all paths for the callback, if any incoming path had one. */
for (i = 0; i < paths->nelts; i++)
{
const char *path = APR_ARRAY_IDX(paths, i, const char *);
if (path[0] == '/')
{
/* Re-allocate the array and note that we found a '/' prefix. */
if (!b.slash_prefix)
{
paths = apr_array_copy(pool, paths);
b.slash_prefix = TRUE;
}
/* Modify each array element that had a '/' prefix */
APR_ARRAY_IDX(paths, i, const char *) = path + 1;
}
}
SVN_ERR(svn_delta_path_driver3(editor, edit_baton,
paths, sort_paths,
path_driver_2_to_3_func, &b,
pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_delta_path_driver(const svn_delta_editor_t *editor,
void *edit_baton,

View File

@ -375,14 +375,12 @@ svn_element__tree_get(const svn_element__tree_t *tree,
return svn_eid__hash_get(tree->e_map, eid);
}
svn_error_t *
void
svn_element__tree_set(svn_element__tree_t *tree,
int eid,
const svn_element__content_t *element)
{
svn_eid__hash_set(tree->e_map, eid, element);
return SVN_NO_ERROR;
}
void

View File

@ -6,7 +6,7 @@ includedir=@includedir@
Name: libsvn_delta
Description: Subversion Delta Library
Version: @PACKAGE_VERSION@
Requires: apr-util-@SVN_APR_MAJOR_VERSION@ apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_subr
Libs: -L${libdir} -lsvn_delta @SVN_ZLIB_LIBS@
Cflags: -I${includedir}
Requires: apr-util-@SVN_APR_MAJOR_VERSION@, apr-@SVN_APR_MAJOR_VERSION@
Requires.private: libsvn_subr
Libs: -L${libdir} -lsvn_delta-1 @SVN_ZLIB_LIBS@
Cflags: -I${includedir}/subversion-1

View File

@ -31,7 +31,6 @@
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_sorts.h"
#include "private/svn_fspath.h"
#include "private/svn_sorts_private.h"
@ -45,6 +44,22 @@ typedef struct dir_stack_t
} dir_stack_t;
/* Push onto dir_stack a new item allocated in POOL and containing
* DIR_BATON and POOL.
*/
static void
push_dir_stack_item(apr_array_header_t *db_stack,
void *dir_baton,
apr_pool_t *pool)
{
dir_stack_t *item = apr_pcalloc(pool, sizeof(*item));
item->dir_baton = dir_baton;
item->pool = pool;
APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item;
}
/* Call EDITOR's open_directory() function with the PATH argument, then
* add the resulting dir baton to the dir baton stack.
*/
@ -72,10 +87,7 @@ open_dir(apr_array_header_t *db_stack,
&db));
/* Now add the dir baton to the stack. */
item = apr_pcalloc(subpool, sizeof(*item));
item->dir_baton = db;
item->pool = subpool;
APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item;
push_dir_stack_item(db_stack, db, subpool);
return SVN_NO_ERROR;
}
@ -131,168 +143,215 @@ count_components(const char *path)
/*** Public interfaces ***/
svn_error_t *
svn_delta_path_driver2(const svn_delta_editor_t *editor,
svn_delta_path_driver3(const svn_delta_editor_t *editor,
void *edit_baton,
const apr_array_header_t *paths,
const apr_array_header_t *relpaths,
svn_boolean_t sort_paths,
svn_delta_path_driver_cb_func_t callback_func,
svn_delta_path_driver_cb_func2_t callback_func,
void *callback_baton,
apr_pool_t *pool)
{
apr_array_header_t *db_stack = apr_array_make(pool, 4, sizeof(void *));
const char *last_path = NULL;
int i = 0;
void *parent_db = NULL, *db = NULL;
const char *path;
svn_delta_path_driver_state_t *state;
int i;
apr_pool_t *subpool, *iterpool;
dir_stack_t *item;
/* Do nothing if there are no paths. */
if (! paths->nelts)
if (! relpaths->nelts)
return SVN_NO_ERROR;
subpool = svn_pool_create(pool);
iterpool = svn_pool_create(pool);
/* sort paths if necessary */
if (sort_paths && paths->nelts > 1)
if (sort_paths && relpaths->nelts > 1)
{
apr_array_header_t *sorted = apr_array_copy(subpool, paths);
apr_array_header_t *sorted = apr_array_copy(subpool, relpaths);
svn_sort__array(sorted, svn_sort_compare_paths);
paths = sorted;
relpaths = sorted;
}
item = apr_pcalloc(subpool, sizeof(*item));
/* If the root of the edit is also a target path, we want to call
the callback function to let the user open the root directory and
do what needs to be done. Otherwise, we'll do the open_root()
ourselves. */
path = APR_ARRAY_IDX(paths, 0, const char *);
if (svn_path_is_empty(path))
{
SVN_ERR(callback_func(&db, NULL, callback_baton, path, subpool));
last_path = path;
i++;
}
else
{
SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, subpool, &db));
}
item->pool = subpool;
item->dir_baton = db;
APR_ARRAY_PUSH(db_stack, void *) = item;
SVN_ERR(svn_delta_path_driver_start(&state,
editor, edit_baton,
callback_func, callback_baton,
pool));
/* Now, loop over the commit items, traversing the URL tree and
driving the editor. */
for (; i < paths->nelts; i++)
for (i = 0; i < relpaths->nelts; i++)
{
const char *pdir;
const char *common = "";
size_t common_len;
const char *relpath;
/* Clear the iteration pool. */
svn_pool_clear(iterpool);
/* Get the next path. */
path = APR_ARRAY_IDX(paths, i, const char *);
relpath = APR_ARRAY_IDX(relpaths, i, const char *);
/*** Step A - Find the common ancestor of the last path and the
current one. For the first iteration, this is just the
empty string. ***/
if (i > 0)
common = (last_path[0] == '/')
? svn_fspath__get_longest_ancestor(last_path, path, iterpool)
: svn_relpath_get_longest_ancestor(last_path, path, iterpool);
common_len = strlen(common);
/*** Step B - Close any directories between the last path and
the new common ancestor, if any need to be closed.
Sometimes there is nothing to do here (like, for the first
iteration, or when the last path was an ancestor of the
current one). ***/
if ((i > 0) && (strlen(last_path) > common_len))
{
const char *rel = last_path + (common_len ? (common_len + 1) : 0);
int count = count_components(rel);
while (count--)
{
SVN_ERR(pop_stack(db_stack, editor));
}
}
/*** Step C - Open any directories between the common ancestor
and the parent of the current path. ***/
if (*path == '/')
pdir = svn_fspath__dirname(path, iterpool);
else
pdir = svn_relpath_dirname(path, iterpool);
if (strlen(pdir) > common_len)
{
const char *piece = pdir + common_len + 1;
while (1)
{
const char *rel = pdir;
/* Find the first separator. */
piece = strchr(piece, '/');
/* Calculate REL as the portion of PDIR up to (but not
including) the location to which PIECE is pointing. */
if (piece)
rel = apr_pstrmemdup(iterpool, pdir, piece - pdir);
/* Open the subdirectory. */
SVN_ERR(open_dir(db_stack, editor, rel, pool));
/* If we found a '/', advance our PIECE pointer to
character just after that '/'. Otherwise, we're
done. */
if (piece)
piece++;
else
break;
}
}
/*** Step D - Tell our caller to handle the current path. ***/
item = APR_ARRAY_IDX(db_stack, db_stack->nelts - 1, void *);
parent_db = item->dir_baton;
subpool = svn_pool_create(pool);
SVN_ERR(callback_func(&db, parent_db, callback_baton, path, subpool));
if (db)
{
item = apr_pcalloc(subpool, sizeof(*item));
item->dir_baton = db;
item->pool = subpool;
APR_ARRAY_PUSH(db_stack, void *) = item;
}
else
{
svn_pool_destroy(subpool);
}
/*** Step E - Save our state for the next iteration. If our
caller opened or added PATH as a directory, that becomes
our LAST_PATH. Otherwise, we use PATH's parent
directory. ***/
/* NOTE: The variable LAST_PATH needs to outlive the loop. */
if (db)
last_path = path; /* lives in a pool outside our control. */
else
last_path = apr_pstrdup(pool, pdir); /* duping into POOL. */
SVN_ERR(svn_delta_path_driver_step(state, relpath, iterpool));
}
/* Destroy the iteration subpool. */
svn_pool_destroy(iterpool);
/* Close down any remaining open directory batons. */
while (db_stack->nelts)
SVN_ERR(svn_delta_path_driver_finish(state, pool));
return SVN_NO_ERROR;
}
struct svn_delta_path_driver_state_t
{
const svn_delta_editor_t *editor;
void *edit_baton;
svn_delta_path_driver_cb_func2_t callback_func;
void *callback_baton;
apr_array_header_t *db_stack;
const char *last_path;
apr_pool_t *pool; /* at least the lifetime of the entire drive */
};
svn_error_t *
svn_delta_path_driver_start(svn_delta_path_driver_state_t **state_p,
const svn_delta_editor_t *editor,
void *edit_baton,
svn_delta_path_driver_cb_func2_t callback_func,
void *callback_baton,
apr_pool_t *pool)
{
svn_delta_path_driver_state_t *state = apr_pcalloc(pool, sizeof(*state));
state->editor = editor;
state->edit_baton = edit_baton;
state->callback_func = callback_func;
state->callback_baton = callback_baton;
state->db_stack = apr_array_make(pool, 4, sizeof(void *));
state->last_path = NULL;
state->pool = pool;
*state_p = state;
return SVN_NO_ERROR;
}
svn_error_t *
svn_delta_path_driver_step(svn_delta_path_driver_state_t *state,
const char *relpath,
apr_pool_t *scratch_pool)
{
const char *pdir;
const char *common = "";
size_t common_len;
apr_pool_t *subpool;
dir_stack_t *item;
void *parent_db, *db;
SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
/* If the first target path is not the root of the edit, we must first
call open_root() ourselves. (If the first target path is the root of
the edit, then we expect the user's callback to do so.) */
if (!state->last_path && !svn_path_is_empty(relpath))
{
SVN_ERR(pop_stack(db_stack, editor));
subpool = svn_pool_create(state->pool);
SVN_ERR(state->editor->open_root(state->edit_baton, SVN_INVALID_REVNUM,
subpool, &db));
push_dir_stack_item(state->db_stack, db, subpool);
}
/*** Step A - Find the common ancestor of the last path and the
current one. For the first iteration, this is just the
empty string. ***/
if (state->last_path)
common = svn_relpath_get_longest_ancestor(state->last_path, relpath,
scratch_pool);
common_len = strlen(common);
/*** Step B - Close any directories between the last path and
the new common ancestor, if any need to be closed.
Sometimes there is nothing to do here (like, for the first
iteration, or when the last path was an ancestor of the
current one). ***/
if ((state->last_path) && (strlen(state->last_path) > common_len))
{
const char *rel = state->last_path + (common_len ? (common_len + 1) : 0);
int count = count_components(rel);
while (count--)
{
SVN_ERR(pop_stack(state->db_stack, state->editor));
}
}
/*** Step C - Open any directories between the common ancestor
and the parent of the current path. ***/
pdir = svn_relpath_dirname(relpath, scratch_pool);
if (strlen(pdir) > common_len)
{
const char *piece = pdir + common_len + 1;
while (1)
{
const char *rel = pdir;
/* Find the first separator. */
piece = strchr(piece, '/');
/* Calculate REL as the portion of PDIR up to (but not
including) the location to which PIECE is pointing. */
if (piece)
rel = apr_pstrmemdup(scratch_pool, pdir, piece - pdir);
/* Open the subdirectory. */
SVN_ERR(open_dir(state->db_stack, state->editor, rel, state->pool));
/* If we found a '/', advance our PIECE pointer to
character just after that '/'. Otherwise, we're
done. */
if (piece)
piece++;
else
break;
}
}
/*** Step D - Tell our caller to handle the current path. ***/
if (state->db_stack->nelts)
{
item = APR_ARRAY_IDX(state->db_stack, state->db_stack->nelts - 1, void *);
parent_db = item->dir_baton;
}
else
parent_db = NULL;
db = NULL; /* predictable behaviour for callbacks that don't set it */
subpool = svn_pool_create(state->pool);
SVN_ERR(state->callback_func(&db,
state->editor, state->edit_baton, parent_db,
state->callback_baton,
relpath, subpool));
if (db)
{
push_dir_stack_item(state->db_stack, db, subpool);
}
else
{
svn_pool_destroy(subpool);
}
/*** Step E - Save our state for the next iteration. If our
caller opened or added PATH as a directory, that becomes
our LAST_PATH. Otherwise, we use PATH's parent
directory. ***/
state->last_path = apr_pstrdup(state->pool, db ? relpath : pdir);
return SVN_NO_ERROR;
}
svn_error_t *
svn_delta_path_driver_finish(svn_delta_path_driver_state_t *state,
apr_pool_t *scratch_pool)
{
/* Close down any remaining open directory batons. */
while (state->db_stack->nelts)
{
SVN_ERR(pop_stack(state->db_stack, state->editor));
}
return SVN_NO_ERROR;

View File

@ -1253,7 +1253,7 @@ svn_diff_file_options_parse(svn_diff_file_options_t *options,
apr_array_cat(argv, args);
APR_ARRAY_PUSH(argv, const char *) = NULL;
apr_getopt_init(&os, pool,
apr_getopt_init(&os, pool,
argv->nelts - 1 /* Exclude trailing NULL */,
(const char *const *) argv->elts);

Some files were not shown because too many files have changed in this diff Show More