Mercurial > hgsubversion
annotate tests/fixtures/rsvn.py @ 1596:04a24a13960f
util: add visitdir() and visitchildrenset() to PrefixMatch
This is done to be compatible with treemanifest repositories.
| author | Pulkit Goyal <pulkit@yandex-team.ru> |
|---|---|
| date | Tue, 20 Nov 2018 15:37:06 +0300 |
| parents | e9af7eba88db |
| children |
| rev | line source |
|---|---|
| 581 | 1 #!/usr/bin/env python2 |
| 2 | |
| 3 # LICENSE | |
| 4 # | |
| 5 # Copyright (c) 2004, Francois Beausoleil | |
| 6 # All rights reserved. | |
| 7 # | |
| 8 # Redistribution and use in source and binary forms, with or without | |
| 9 # modification, are permitted provided that the following conditions | |
| 10 # are met: | |
| 11 # | |
| 12 # * Redistributions of source code must retain the above copyright | |
| 13 # notice, this list of conditions and the following disclaimer. | |
| 14 # * Redistributions in binary form must reproduce the above copyright | |
| 15 # notice, this list of conditions and the following disclaimer in | |
| 16 # the documentation and/or other materials provided with the | |
| 17 # distribution. | |
| 18 # * Neither the name of the Francois Beausoleil nor the names of its | |
| 19 # contributors may be used to endorse or promote products derived | |
| 20 # from this software without specific prior written permission. | |
| 21 # | |
| 22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 25 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 26 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 27 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 33 | |
| 34 import getopt | |
| 35 import sys | |
| 36 import os | |
| 37 import re | |
| 38 import traceback | |
| 39 from svn import core, repos, fs | |
| 40 | |
| 41 VERSION='$Id: rsvn.py 20 2005-09-23 15:08:08Z fbos $' | |
| 42 RCOPY_RE = re.compile('^\s*rcopy\s+(.+)\s+(.+)$') | |
| 43 RMOVE_RE = re.compile('^\s*rmove\s+(.+)\s+(.+)$') | |
| 44 RMKDIR_RE = re.compile('^\s*rmkdir\s+(.+)$') | |
| 45 RDELETE_RE = re.compile('^\s*rdelete\s+(.+)$') | |
| 46 COMMENT_RE = re.compile('(?:^\s*#)|(?:^\s*$)') | |
| 47 | |
| 48 def usage(error=None): | |
| 49 if error: | |
| 50 print 'Error: %s\n' % error | |
| 51 print 'USAGE: %s --message=MESSAGE repos_path [--username=USERNAME]' % ( | |
| 52 os.path.basename(sys.argv[0])) | |
| 53 print '' | |
| 54 print ' --help, -h print this usage message and exit with success' | |
| 55 print ' --version print the version number' | |
| 56 print ' --username=USERNAME Username to execute the commands under' | |
| 57 print ' --message=LOG_MSG Log message to execute the commit with' | |
| 58 print '' | |
| 59 print 'Reads STDIN and parses the following commands, to execute them on the server, ' | |
| 60 print 'all within the same transaction:' | |
| 61 print '' | |
| 62 print ' rcopy SRC DEST Copy the HEAD revision of a file or folder' | |
| 63 print ' rmove SRC DEST Copy + delete the HEAD revision of a file or folder' | |
| 64 print ' rdelete TARGET Deletes something from the repository' | |
| 65 print ' rmkdir TARGET Creates a new folder (must create parents first)' | |
| 66 print ' # Initiates a comment' | |
| 67 print '' | |
| 68 # 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | |
| 69 | |
| 70 | |
| 71 class Transaction: | |
| 72 """Represents a transaction in a Subversion repository | |
| 73 | |
| 74 Transactions are long-lived objects which exist in the repository, | |
| 75 and are used to build an intermediate representation of a new | |
| 76 revision. Once the transaction is committed, the repository | |
| 77 bumps the revision number, and links the new transaction in the | |
| 78 Subversion filesystem.""" | |
| 79 | |
| 80 def __init__(self, repository, rev, username, message, pool, logger=None): | |
| 81 if logger: | |
| 82 self.logger = logger | |
| 83 else: | |
| 84 self.logger = sys.stdout | |
| 85 self.pool = pool | |
| 86 self.rev = rev | |
| 87 | |
| 88 self.fsptr = repos.svn_repos_fs(repository) | |
| 89 self.rev_root = fs.revision_root(self.fsptr, self.rev, | |
| 90 self.pool) | |
| 91 self.txnp = repos.svn_repos_fs_begin_txn_for_commit( | |
| 92 repository, self.rev, username, message, self.pool) | |
| 93 self.txn_root = fs.txn_root(self.txnp, self.pool) | |
| 94 self.log('Base revision %d\n' % rev) | |
| 95 | |
| 96 def commit(self): | |
| 97 values = fs.commit_txn(self.txnp, self.pool) | |
| 98 return values[1] | |
| 99 | |
| 100 def rollback(self): | |
| 101 fs.abort_txn(self.txnp, self.pool) | |
| 102 | |
| 103 def copy(self, src, dest, subpool): | |
| 104 self.log('A + %s\n' % dest) | |
| 105 fs.copy(self.rev_root, src, self.txn_root, dest, subpool) | |
| 106 | |
| 107 def delete(self, entry, subpool): | |
| 108 self.log('D %s\n' % entry) | |
| 109 fs.delete(self.txn_root, entry, subpool) | |
| 110 | |
| 111 def mkdir(self, entry, subpool): | |
| 112 self.log('A %s\n' % entry) | |
| 113 fs.make_dir(self.txn_root, entry, subpool) | |
| 114 | |
| 115 def move(self, src, dest, subpool): | |
| 116 self.copy(src, dest, subpool) | |
| 117 self.delete(src, subpool) | |
| 118 | |
| 119 def log(self, msg): | |
| 120 self.logger.write(msg) | |
| 121 | |
| 122 | |
| 123 class Repository: | |
| 124 """Represents a Subversion repository, and allows common operations | |
| 125 on it.""" | |
| 126 | |
| 127 def __init__(self, repos_path, pool, logger=None): | |
| 128 if logger: | |
| 129 self.logger = logger | |
| 130 else: | |
| 131 self.logger = sys.stdout | |
| 132 self.pool = pool | |
| 133 assert self.pool | |
| 134 | |
| 135 self.repo = repos.svn_repos_open(repos_path, self.pool) | |
| 136 self.fsptr = repos.svn_repos_fs(self.repo) | |
| 137 | |
| 138 def get_youngest(self): | |
| 139 """Returns the youngest revision in the repository.""" | |
| 140 return fs.youngest_rev(self.fsptr, self.pool) | |
| 141 | |
| 142 def begin(self, username, log_msg): | |
| 143 """Initiate a new Transaction""" | |
| 144 return Transaction(self.repo, self.get_youngest(), username, | |
| 145 log_msg, self.pool, self.logger) | |
| 146 | |
| 147 def close(self): | |
| 148 """Close the repository, aborting any uncommitted transactions""" | |
| 149 core.svn_pool_destroy(self.pool) | |
| 150 core.apr_terminate() | |
| 151 | |
| 152 def subpool(self): | |
| 153 """Instantiates a new pool from the master pool""" | |
| 154 return core.svn_pool_create(self.pool) | |
| 155 | |
| 156 def delete_pool(self, pool): | |
| 157 """Deletes the passed-in pool. Returns None, to assign to pool in | |
| 158 caller.""" | |
| 159 core.svn_pool_destroy(pool) | |
| 160 return None | |
| 161 | |
| 162 def rsvn(pool): | |
| 163 log_msg = None | |
| 164 | |
| 165 try: | |
| 166 opts, args = getopt.getopt(sys.argv[1:], 'vh', | |
| 167 ["help", "username=", "message=", "version"]) | |
| 168 except getopt.GetoptError, e: | |
| 169 sys.stderr.write(str(e) + '\n\n') | |
| 170 usage() | |
| 171 sys.exit(1) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
172 |
| 581 | 173 for opt, value in opts: |
| 174 if opt == '--version': | |
| 175 print '%s version %s' % (os.path.basename(sys.argv[0]), VERSION) | |
| 176 sys.exit(0) | |
| 177 elif opt == '--help' or opt == '-h': | |
| 178 usage() | |
| 179 sys.exit(0) | |
| 180 elif opt == '--username': | |
| 181 username = value | |
| 182 elif opt == '--message': | |
| 183 log_msg = value | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
184 |
| 581 | 185 if log_msg == None: |
| 186 usage('Missing --message argument') | |
| 187 sys.exit(1) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
188 |
| 581 | 189 if len(args) != 1: |
| 190 usage('Missing repository path argument') | |
| 191 sys.exit(1) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
192 |
| 581 | 193 repos_path = args[0] |
| 194 print 'Accessing repository at [%s]' % repos_path | |
| 195 | |
| 196 repository = Repository(repos_path, pool) | |
| 197 sub = repository.subpool() | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
198 |
| 581 | 199 try: |
| 200 txn = repository.begin(username, log_msg) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
201 |
| 581 | 202 # Read commands from STDIN |
| 203 lineno = 0 | |
| 204 for line in sys.stdin: | |
| 205 lineno += 1 | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
206 |
| 581 | 207 core.svn_pool_clear(sub) |
| 208 try: | |
| 209 if COMMENT_RE.search(line): | |
| 210 continue | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
211 |
| 581 | 212 match = RCOPY_RE.search(line) |
| 213 if match: | |
| 214 src = match.group(1) | |
| 215 dest = match.group(2) | |
| 216 txn.copy(src, dest, sub) | |
| 217 continue | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
218 |
| 581 | 219 match = RMOVE_RE.search(line) |
| 220 if match: | |
| 221 src = match.group(1) | |
| 222 dest = match.group(2) | |
| 223 txn.move(src, dest, sub) | |
| 224 continue | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
225 |
| 581 | 226 match = RMKDIR_RE.search(line) |
| 227 if match: | |
| 228 entry = match.group(1) | |
| 229 txn.mkdir(entry, sub) | |
| 230 continue | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
231 |
| 581 | 232 match = RDELETE_RE.search(line) |
| 233 if match: | |
| 234 entry = match.group(1) | |
| 235 txn.delete(entry, sub) | |
| 236 continue | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
237 |
| 581 | 238 raise NameError, ('Unknown command [%s] on line %d' % |
| 239 (line, lineno)) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
240 |
| 581 | 241 except: |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
242 sys.stderr.write(('Exception occured while processing line %d:\n' % |
| 581 | 243 lineno)) |
| 244 etype, value, tb = sys.exc_info() | |
| 245 traceback.print_exception(etype, value, tb, None, sys.stderr) | |
| 246 sys.stderr.write('\n') | |
| 247 txn.rollback() | |
| 248 sys.exit(1) | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
249 |
| 581 | 250 new_rev = txn.commit() |
| 251 print '\nCommitted revision %d.' % new_rev | |
|
832
e9af7eba88db
globally: clean up whitespace around operators and commas to conform with PEP8
Yonggang Luo <luoyonggang@gmail.com>
parents:
581
diff
changeset
|
252 |
| 581 | 253 finally: |
| 254 print '\nRepository closed.' | |
| 255 | |
| 256 def main(): | |
| 257 core.run_app(rsvn) | |
| 258 | |
| 259 if __name__ == '__main__': | |
| 260 main() |
