annotate hgsubversion/maps.py @ 1550:67b28d657f62

sqliterevmap: break ".hashes()" cycle in a safer way The `fromsvn()` revset implementation could cause weakref error when using sqliterevmap like: File "hgsubversion/util.py", line 357, in <lambda> return subset.filter(lambda r: tonode(r) in hashes) File "hgsubversion/maps.py", line 542, in __contains__ return self.get(key) != None File "hgsubversion/maps.py", line 533, in get for row in self.revmap._query( ReferenceError: weakly-referenced object no longer exists Basically the seemingly harmless assignment could break surprisingly: # dangerous: `hashes` does not have a reference of `meta.revmap` and may # become unavailable after `meta`, `revmap` being released by refcount. hashes = meta.revmap.hashes() The above syntax is nice to support while avoiding cycles is also nice. This patch removes `revmap._hashes` so the revmap no longer owns a reference of a `ReverseRevMap` object so the `ReverseRevMap` object no longer needs to use weakref for `self.revmap`. This could actually be caught by `comprehensive/test_sqlite_revmap.py`. I was not careful enough verifying the "fromsvn()" patch.
author Jun Wu <quark@fb.com>
date Thu, 21 Dec 2017 17:39:52 -0800
parents 09476d758b59
children cff81f35b31e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
1 ''' Module for self-contained maps. '''
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
2
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
3 import collections
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
4 import contextlib
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
5 import errno
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
6 import os
1394
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
7 import re
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
8 import sqlite3
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
9 import sys
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
10 import weakref
1439
ab15749252b0 TagMap: stop automagically running 'hg svn rebuildmeta'
Augie Fackler <raf@durin42.com>
parents: 1438
diff changeset
11 from mercurial import error
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
12 from mercurial import util as hgutil
1253
c54214bb6c4e maps: avoid O(n) property lookups on the node module
Siddharth Agarwal <sid0@fb.com>
parents: 1252
diff changeset
13 from mercurial.node import bin, hex, nullid
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
14
1374
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
15 import subprocess
829
5061640fe5bc revmap: load/save _youngest using new load_string and save_string API
Yonggang Luo <luoyonggang@gmail.com>
parents: 826
diff changeset
16 import util
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
17
1383
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
18 class BaseMap(dict):
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
19 '''A base class for the different type of mappings: author, branch, and
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
20 tags.'''
1441
e79ff1a85938 BaseMap: no longer take a meta as an argument
Augie Fackler <raf@durin42.com>
parents: 1440
diff changeset
21 def __init__(self, ui, filepath):
1383
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
22 super(BaseMap, self).__init__()
1441
e79ff1a85938 BaseMap: no longer take a meta as an argument
Augie Fackler <raf@durin42.com>
parents: 1440
diff changeset
23 self._ui = ui
1383
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
24
1394
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
25 self._commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
1401
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
26 self.syntaxes = ('re', 'glob')
1394
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
27
1441
e79ff1a85938 BaseMap: no longer take a meta as an argument
Augie Fackler <raf@durin42.com>
parents: 1440
diff changeset
28 self._filepath = filepath
e79ff1a85938 BaseMap: no longer take a meta as an argument
Augie Fackler <raf@durin42.com>
parents: 1440
diff changeset
29 self.load(filepath)
1383
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
30
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
31 # Append mappings specified from the commandline. A little
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
32 # magic here: our name in the config mapping is the same as
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
33 # the class name lowercased.
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
34 clmap = util.configpath(self._ui, self.mapname())
1383
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
35 if clmap:
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
36 self.load(clmap)
73c76f99ca08 maps: add a basemap class
Sean Farley <sean.michael.farley@gmail.com>
parents: 1382
diff changeset
37
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
38 @classmethod
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
39 def mapname(cls):
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
40 return cls.__name__.lower()
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
41
1395
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
42 def _findkey(self, key):
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
43 '''Takes a string and finds the first corresponding key that matches
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
44 via regex'''
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
45 if not key:
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
46 return None
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
47
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
48 # compile a new regex key if we're given a string; can't use
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
49 # hgutil.compilere since we need regex.sub
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
50 k = key
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
51 if isinstance(key, str):
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
52 k = re.compile(re.escape(key))
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
53
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
54 # preference goes to matching the exact pattern, i.e. 'foo' should
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
55 # first match 'foo' before trying regexes
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
56 for regex in self:
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
57 if regex.pattern == k.pattern:
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
58 return regex
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
59
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
60 # if key isn't a string, then we are done; nothing matches
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
61 if not isinstance(key, str):
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
62 return None
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
63
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
64 # now we test the regex; the above loop will be faster and is
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
65 # equivalent to not having regexes (i.e. just doing string compares)
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
66 for regex in self:
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
67 if regex.search(key):
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
68 return regex
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
69 return None
53184be1b1fd maps: add _findkey method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1394
diff changeset
70
1396
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
71 def get(self, key, default=None):
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
72 '''Similar to dict.get, except we use our own matcher, _findkey.'''
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
73 if self._findkey(key):
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
74 return self[key]
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
75 return default
77594c88d91f maps: add custom get method
Sean Farley <sean.michael.farley@gmail.com>
parents: 1395
diff changeset
76
1397
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
77 def __getitem__(self, key):
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
78 '''Similar to dict.get, except we use our own matcher, _findkey. If the key is
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
79 a string, then we can use our regex matching to map its value.
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
80 '''
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
81 k = self._findkey(key)
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
82 val = super(BaseMap, self).__getitem__(k)
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
83
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
84 # if key is a string then we can transform it using our regex, else we
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
85 # don't have enough information, so we just return the val
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
86 if isinstance(key, str):
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
87 val = k.sub(val, key)
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
88
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
89 return val
304fdb9810a6 maps: add custom __getitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1396
diff changeset
90
1398
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
91 def __setitem__(self, key, value):
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
92 '''Similar to dict.__setitem__, except we compile the string into a regex, if
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
93 need be.
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
94 '''
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
95 # try to find the regex already in the map
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
96 k = self._findkey(key)
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
97 # if we found one, then use it
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
98 if k:
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
99 key = k
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
100 # else make a new regex
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
101 if isinstance(key, str):
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
102 key = re.compile(re.escape(key))
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
103 super(BaseMap, self).__setitem__(key, value)
75745298d99d maps: add custom __setitem__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1397
diff changeset
104
1399
3b96075bffa7 maps: add custom __contains__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1398
diff changeset
105 def __contains__(self, key):
3b96075bffa7 maps: add custom __contains__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1398
diff changeset
106 '''Similar to dict.get, except we use our own matcher, _findkey.'''
3b96075bffa7 maps: add custom __contains__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1398
diff changeset
107 return self._findkey(key) is not None
3b96075bffa7 maps: add custom __contains__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1398
diff changeset
108
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
109 def load(self, path):
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
110 '''Load mappings from a file at the specified path.'''
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
111 path = os.path.expandvars(path)
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
112 if not os.path.exists(path):
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
113 return
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
114
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
115 writing = False
1431
066c08918060 BaseMap: record filename on self._filename
Augie Fackler <raf@durin42.com>
parents: 1430
diff changeset
116 mapfile = self._filepath
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
117 if path != mapfile:
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
118 writing = open(mapfile, 'a')
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
119
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
120 self._ui.debug('reading %s from %s\n' % (self.mapname() , path))
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
121 f = open(path, 'r')
1401
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
122 syntax = ''
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
123 for number, line in enumerate(f):
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
124
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
125 if writing:
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
126 writing.write(line)
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
127
1394
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
128 # strip out comments
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
129 if "#" in line:
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
130 # remove comments prefixed by an even number of escapes
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
131 line = self._commentre.sub(r'\1', line)
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
132 # fixup properly escaped comments that survived the above
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
133 line = line.replace("\\#", "#")
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
134 line = line.rstrip()
c4055968f030 maps: use regex for better comment handling
Sean Farley <sean.michael.farley@gmail.com>
parents: 1393
diff changeset
135 if not line:
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
136 continue
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
137
1401
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
138 if line.startswith('syntax:'):
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
139 s = line[7:].strip()
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
140 syntax = ''
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
141 if s in self.syntaxes:
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
142 syntax = s
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
143 continue
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
144 pat = syntax
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
145 for s in self.syntaxes:
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
146 if line.startswith(s + ':'):
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
147 pat = s
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
148 line = line[len(s) + 1:]
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
149 break
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
150
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
151 # split on the first '='
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
152 try:
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
153 src, dst = line.split('=', 1)
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
154 except (IndexError, ValueError):
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
155 msg = 'ignoring line %i in %s %s: %s\n'
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
156 self._ui.status(msg % (number, self.mapname(), path,
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
157 line.rstrip()))
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
158 continue
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
159
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
160 src = src.strip()
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
161 dst = dst.strip()
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
162
1401
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
163 if pat != 're':
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
164 src = re.escape(src)
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
165 if pat == 'glob':
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
166 src = src.replace('\\*', '.*')
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
167 src = re.compile(src)
70cb6ba038fa maps: add ability to parse a regex or glob
Sean Farley <sean.michael.farley@gmail.com>
parents: 1400
diff changeset
168
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
169 if src not in self:
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
170 self._ui.debug('adding %s to %s\n' % (src, self.mapname()))
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
171 elif dst != self[src]:
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
172 msg = 'overriding %s: "%s" to "%s" (%s)\n'
1440
4d3a51e82147 BaseMap: extract filename attribute magic into a classmethod
Augie Fackler <raf@durin42.com>
parents: 1439
diff changeset
173 self._ui.status(msg % (self.mapname(), self[src], dst, src))
1384
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
174 self[src] = dst
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
175
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
176 f.close()
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
177 if writing:
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
178 writing.close()
2d1d05e6e46c maps: add a load method to base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1383
diff changeset
179
1385
9139d9295a36 maps: make author map inherit from base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1384
diff changeset
180 class AuthorMap(BaseMap):
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
181 '''A mapping from Subversion-style authors to Mercurial-style
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
182 authors, and back. The data is stored persistently on disk.
322
05cd4a5138bf Move some .warn() calls to noisy levels instead.
Augie Fackler <durin42@gmail.com>
parents: 310
diff changeset
183
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
184 If the 'hgsubversion.defaultauthors' configuration option is set to false,
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
185 attempting to obtain an unknown author will fail with an Abort.
1188
38dd8721fb0d maps: remove trailing whitespace
Sean Farley <sean.michael.farley@gmail.com>
parents: 1187
diff changeset
186
1097
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
187 If the 'hgsubversion.caseignoreauthors' configuration option is set to true,
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
188 the userid from Subversion is always compared lowercase.
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
189 '''
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
190
1442
a0ba38def79b AuthorMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1441
diff changeset
191 def __init__(self, ui, filepath, defaulthost, caseignoreauthors,
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
192 mapauthorscmd, defaultauthors):
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
193 '''Initialise a new AuthorMap.
322
05cd4a5138bf Move some .warn() calls to noisy levels instead.
Augie Fackler <durin42@gmail.com>
parents: 310
diff changeset
194
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
195 The ui argument is used to print diagnostic messages.
322
05cd4a5138bf Move some .warn() calls to noisy levels instead.
Augie Fackler <durin42@gmail.com>
parents: 310
diff changeset
196
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
197 The path argument is the location of the backing store,
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
198 typically .hg/svn/authors.
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
199 '''
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
200 if defaulthost:
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
201 self.defaulthost = '@%s' % defaulthost.lstrip('@')
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
202 else:
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
203 self.defaulthost = ''
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
204 self._caseignoreauthors = caseignoreauthors
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
205 self._mapauthorscmd = mapauthorscmd
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
206 self._defaulthost = defaulthost
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
207 self._defaultauthors = defaultauthors
1194
49791c40a8a5 maps: change authormap to initialize with an svnmeta object
Sean Farley <sean.michael.farley@gmail.com>
parents: 1193
diff changeset
208
1442
a0ba38def79b AuthorMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1441
diff changeset
209 super(AuthorMap, self).__init__(ui, filepath)
1193
a55339d35066 maps: load commandline authormap in __init__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1188
diff changeset
210
1400
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
211 def _lowercase(self, key):
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
212 '''Determine whether or not to lowercase a str or regex using the
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
213 meta.caseignoreauthors.'''
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
214 k = key
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
215 if self._caseignoreauthors:
1400
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
216 if isinstance(key, str):
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
217 k = key.lower()
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
218 else:
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
219 k = re.compile(key.pattern.lower())
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
220 return k
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
221
1379
367e65989b41 maps: add custom __setitem__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1375
diff changeset
222 def __setitem__(self, key, value):
367e65989b41 maps: add custom __setitem__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1375
diff changeset
223 '''Similar to dict.__setitem__, except we check caseignoreauthors to
367e65989b41 maps: add custom __setitem__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1375
diff changeset
224 use lowercase string or not
367e65989b41 maps: add custom __setitem__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1375
diff changeset
225 '''
1400
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
226 super(AuthorMap, self).__setitem__(self._lowercase(key), value)
1379
367e65989b41 maps: add custom __setitem__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1375
diff changeset
227
1380
332ad9ea579b maps: add custom __contains__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1379
diff changeset
228 def __contains__(self, key):
332ad9ea579b maps: add custom __contains__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1379
diff changeset
229 '''Similar to dict.__contains__, except we check caseignoreauthors to
332ad9ea579b maps: add custom __contains__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1379
diff changeset
230 use lowercase string or not
332ad9ea579b maps: add custom __contains__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1379
diff changeset
231 '''
1400
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
232 return super(AuthorMap, self).__contains__(self._lowercase(key))
1380
332ad9ea579b maps: add custom __contains__ to author map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1379
diff changeset
233
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
234 def __getitem__(self, author):
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
235 ''' Similar to dict.__getitem__, except in case of an unknown author.
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
236 In such cases, a new value is generated and added to the dictionary
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
237 as well as the backing store. '''
735
c2b9e08ecf10 maps: map a missing author to '(no author)'
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 729
diff changeset
238 if author is None:
c2b9e08ecf10 maps: map a missing author to '(no author)'
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 729
diff changeset
239 author = '(no author)'
1097
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
240
1400
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
241 if not isinstance(author, str):
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
242 return super(AuthorMap, self).__getitem__(author)
3e264851f879 maps: protect author map functions from regexes
Sean Farley <sean.michael.farley@gmail.com>
parents: 1399
diff changeset
243
1196
878372849175 maps: use meta.caseignoreauthors intead of accessing ui directly
Sean Farley <sean.michael.farley@gmail.com>
parents: 1195
diff changeset
244 search_author = author
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
245 if self._caseignoreauthors:
1097
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
246 search_author = author.lower()
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
247
1374
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
248 result = None
1097
e015cd34168d authormap: allow case-insensitive authormaps for easier conversions
maugustin
parents: 976
diff changeset
249 if search_author in self:
1382
d996850ac4e8 maps: call super directly instead of self.super
Sean Farley <sean.michael.farley@gmail.com>
parents: 1381
diff changeset
250 result = super(AuthorMap, self).__getitem__(search_author)
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
251 elif self._mapauthorscmd:
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
252 cmd = self._mapauthorscmd % author
1375
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
253 process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
254 output, err = process.communicate()
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
255 retcode = process.poll()
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
256 if retcode:
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
257 msg = 'map author command "%s" exited with error'
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
258 raise hgutil.Abort(msg % cmd)
abc87a62ff51 maps: remove python2.7ism from dynamic author mapping
Mateusz Kwapich <mitrandir@fb.com>
parents: 1374
diff changeset
259 self[author] = result = output.strip()
1374
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
260 if not result:
1429
3a723188051e AuthorMap: make local implementation concerns stop using self.meta
Augie Fackler <raf@durin42.com>
parents: 1428
diff changeset
261 if self._defaultauthors:
1374
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
262 self[author] = result = '%s%s' % (author, self.defaulthost)
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
263 msg = 'substituting author "%s" for default "%s"\n'
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
264 self._ui.debug(msg % (author, result))
1374
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
265 else:
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
266 msg = 'author %s has no entry in the author map!'
a17d8874a099 Added dynamic author mapping.
Jerome M. BERGER <jeberger@free.fr>
parents: 1356
diff changeset
267 raise hgutil.Abort(msg % author)
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
268 self._ui.debug('mapping author "%s" to "%s"\n' % (author, result))
307
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
269 return result
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
270
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
271 def reverselookup(self, author):
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
272 for svnauthor, hgauthor in self.iteritems():
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
273 if author == hgauthor:
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
274 return svnauthor
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
275 else:
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
276 # Mercurial incorrectly splits at e.g. '.', so we roll our own.
1d48d9a34c19 Put authormap into a separate file, and make it much better too.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents:
diff changeset
277 return author.rsplit('@', 1)[0]
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
278
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
279
728
cfefeefad199 rename TagMap to Tags, to free up the TagMap name
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 725
diff changeset
280 class Tags(dict):
519
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
281 """Map tags to converted node identifier.
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
282
729
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
283 tag names are non-empty strings. Tags are saved in a file
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
284 called tagmap, for backwards compatibility reasons.
519
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
285 """
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
286 VERSION = 2
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
287
1445
5dbc6356a0d3 Tags: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1444
diff changeset
288 def __init__(self, ui, filepath, endrev=None):
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
289 dict.__init__(self)
1445
5dbc6356a0d3 Tags: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1444
diff changeset
290 self._filepath = filepath
5dbc6356a0d3 Tags: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1444
diff changeset
291 self._ui = ui
725
c787147fa3b7 fix some style nits
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 647
diff changeset
292 self.endrev = endrev
1432
a2ef2c1e3644 TagMap: record filepath explicitly
Augie Fackler <raf@durin42.com>
parents: 1431
diff changeset
293 if os.path.isfile(self._filepath):
1187
30b2139c3931 maps: change tags init to accept svnmeta not a repo
Sean Farley <sean.michael.farley@gmail.com>
parents: 1186
diff changeset
294 self._load()
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
295 else:
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
296 self._write()
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
297
1187
30b2139c3931 maps: change tags init to accept svnmeta not a repo
Sean Farley <sean.michael.farley@gmail.com>
parents: 1186
diff changeset
298 def _load(self):
1432
a2ef2c1e3644 TagMap: record filepath explicitly
Augie Fackler <raf@durin42.com>
parents: 1431
diff changeset
299 f = open(self._filepath)
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
300 ver = int(f.readline())
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
301 if ver < self.VERSION:
1439
ab15749252b0 TagMap: stop automagically running 'hg svn rebuildmeta'
Augie Fackler <raf@durin42.com>
parents: 1438
diff changeset
302 raise error.Abort(
ab15749252b0 TagMap: stop automagically running 'hg svn rebuildmeta'
Augie Fackler <raf@durin42.com>
parents: 1438
diff changeset
303 'tag map outdated, please run `hg svn rebuildmeta`')
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
304 elif ver != self.VERSION:
891
83cc6e9e8425 kill all 'print' statements in the extension proper
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 889
diff changeset
305 raise hgutil.Abort('tagmap too new -- please upgrade')
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
306 for l in f:
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
307 ha, revision, tag = l.split(' ', 2)
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
308 revision = int(revision)
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
309 tag = tag[:-1]
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
310 if self.endrev is not None and revision > self.endrev:
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
311 break
519
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
312 if not tag:
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
313 continue
1253
c54214bb6c4e maps: avoid O(n) property lookups on the node module
Siddharth Agarwal <sid0@fb.com>
parents: 1252
diff changeset
314 dict.__setitem__(self, tag, bin(ha))
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
315 f.close()
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
316
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
317 def _write(self):
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
318 assert self.endrev is None
1432
a2ef2c1e3644 TagMap: record filepath explicitly
Augie Fackler <raf@durin42.com>
parents: 1431
diff changeset
319 f = open(self._filepath, 'w')
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
320 f.write('%s\n' % self.VERSION)
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
321 f.close()
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
322
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
323 def update(self, other):
725
c787147fa3b7 fix some style nits
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 647
diff changeset
324 for k, v in other.iteritems():
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
325 self[k] = v
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
326
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
327 def __contains__(self, tag):
593
eb16630bceb1 maps: fix a % formatting bug
Augie Fackler <durin42@gmail.com>
parents: 579
diff changeset
328 return (tag and dict.__contains__(self, tag)
1253
c54214bb6c4e maps: avoid O(n) property lookups on the node module
Siddharth Agarwal <sid0@fb.com>
parents: 1252
diff changeset
329 and dict.__getitem__(self, tag) != nullid)
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
330
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
331 def __getitem__(self, tag):
519
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
332 if tag and tag in self:
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
333 return dict.__getitem__(self, tag)
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
334 raise KeyError()
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
335
453
bb612e625be6 tags: handle copyfrom old versions of tags more correctly
Augie Fackler <durin42@gmail.com>
parents: 448
diff changeset
336 def __setitem__(self, tag, info):
519
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
337 if not tag:
247110c633f7 maps: TagMap tags are non-empty strings
Patrick Mezard <pmezard@gmail.com>
parents: 460
diff changeset
338 raise hgutil.Abort('tag cannot be empty')
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
339 ha, revision = info
1432
a2ef2c1e3644 TagMap: record filepath explicitly
Augie Fackler <raf@durin42.com>
parents: 1431
diff changeset
340 f = open(self._filepath, 'a')
1253
c54214bb6c4e maps: avoid O(n) property lookups on the node module
Siddharth Agarwal <sid0@fb.com>
parents: 1252
diff changeset
341 f.write('%s %s %s\n' % (hex(ha), revision, tag))
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
342 f.close()
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
343 dict.__setitem__(self, tag, ha)
448
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
344
fbc7cf4fd701 tags: reinstate a tag map file in a better way
Augie Fackler <durin42@gmail.com>
parents: 430
diff changeset
345
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
346 class RevMap(dict):
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
347
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
348 VERSION = 1
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
349
1455
8cfe074cd463 maps: use util.fileproperty for RevMap.lastpulled
Jun Wu <quark@fb.com>
parents: 1449
diff changeset
350 lastpulled = util.fileproperty('_lastpulled', lambda x: x._lastpulled_file,
8cfe074cd463 maps: use util.fileproperty for RevMap.lastpulled
Jun Wu <quark@fb.com>
parents: 1449
diff changeset
351 default=0, deserializer=int)
8cfe074cd463 maps: use util.fileproperty for RevMap.lastpulled
Jun Wu <quark@fb.com>
parents: 1449
diff changeset
352
1446
2eba84031a78 RevMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1445
diff changeset
353 def __init__(self, revmap_path, lastpulled_path):
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
354 dict.__init__(self)
1446
2eba84031a78 RevMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1445
diff changeset
355 self._filepath = revmap_path
2eba84031a78 RevMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1445
diff changeset
356 self._lastpulled_file = lastpulled_path
1294
9a722b5246df maps: cache hashes() for the revmap
Mateusz Kwapich <mitrandir@fb.com>
parents: 1254
diff changeset
357 self._hashes = None
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
358 # disable iteration to have a consistent interface with SqliteRevMap
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
359 # it's less about performance since RevMap needs iteration internally
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
360 self._allowiter = False
1183
09b20039192c maps: change revmap init to accept svnmeta not a repo
Sean Farley <sean.michael.farley@gmail.com>
parents: 1182
diff changeset
361
1434
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
362 self.firstpulled = 0
1430
48beb467b2e5 RevMap: use self._filepath instead of using meta
Augie Fackler <raf@durin42.com>
parents: 1429
diff changeset
363 if os.path.isfile(self._filepath):
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
364 self._load()
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
365 else:
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
366 self._write()
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
367
415
b17b2969861c svnmeta: move revmap methods, make last_known_revision() more efficient
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 409
diff changeset
368 def hashes(self):
1294
9a722b5246df maps: cache hashes() for the revmap
Mateusz Kwapich <mitrandir@fb.com>
parents: 1254
diff changeset
369 if self._hashes is None:
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
370 self._hashes = dict((v, k) for (k, v) in self._origiteritems())
1294
9a722b5246df maps: cache hashes() for the revmap
Mateusz Kwapich <mitrandir@fb.com>
parents: 1254
diff changeset
371 return self._hashes
415
b17b2969861c svnmeta: move revmap methods, make last_known_revision() more efficient
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 409
diff changeset
372
1472
cf79525f507c maps: change branchedits to accept revnum directly
Jun Wu <quark@fb.com>
parents: 1470
diff changeset
373 def branchedits(self, branch, revnum):
cf79525f507c maps: change branchedits to accept revnum directly
Jun Wu <quark@fb.com>
parents: 1470
diff changeset
374 check = lambda x: x[0][1] == branch and x[0][0] < revnum
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
375 return sorted(filter(check, self._origiteritems()), reverse=True)
415
b17b2969861c svnmeta: move revmap methods, make last_known_revision() more efficient
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 409
diff changeset
376
1422
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
377 def branchmaxrevnum(self, branch, maxrevnum):
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
378 result = 0
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
379 for num, br in self._origiterkeys():
1422
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
380 if br == branch and num <= maxrevnum and num > result:
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
381 result = num
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
382 return result
372afb75f465 maps: add the "branchmaxrevnum" method to RevMap
Jun Wu <quark@fb.com>
parents: 1421
diff changeset
383
1419
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
384 @property
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
385 def lasthash(self):
1421
0094f222c5dc maps: make readmapfile of RevMap a private instance method
Jun Wu <quark@fb.com>
parents: 1419
diff changeset
386 lines = list(self._readmapfile())
1419
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
387 if not lines:
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
388 return None
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
389 return bin(lines[-1].split(' ', 2)[1])
2e4145e452cd maps: add "lasthash" property to RevMap
Jun Wu <quark@fb.com>
parents: 1414
diff changeset
390
1413
951a87f2f2bd maps: add the "revhashes" method to RevMap
Jun Wu <quark@fb.com>
parents: 1412
diff changeset
391 def revhashes(self, revnum):
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
392 for key, value in self._origiteritems():
1413
951a87f2f2bd maps: add the "revhashes" method to RevMap
Jun Wu <quark@fb.com>
parents: 1412
diff changeset
393 if key[0] == revnum:
951a87f2f2bd maps: add the "revhashes" method to RevMap
Jun Wu <quark@fb.com>
parents: 1412
diff changeset
394 yield value
951a87f2f2bd maps: add the "revhashes" method to RevMap
Jun Wu <quark@fb.com>
parents: 1412
diff changeset
395
1411
025e849d22f0 maps: add the "clear" method to RevMap
Jun Wu <quark@fb.com>
parents: 1401
diff changeset
396 def clear(self):
025e849d22f0 maps: add the "clear" method to RevMap
Jun Wu <quark@fb.com>
parents: 1401
diff changeset
397 self._write()
025e849d22f0 maps: add the "clear" method to RevMap
Jun Wu <quark@fb.com>
parents: 1401
diff changeset
398 dict.clear(self)
025e849d22f0 maps: add the "clear" method to RevMap
Jun Wu <quark@fb.com>
parents: 1401
diff changeset
399 self._hashes = None
025e849d22f0 maps: add the "clear" method to RevMap
Jun Wu <quark@fb.com>
parents: 1401
diff changeset
400
1434
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
401 def batchset(self, items, lastpulled):
1412
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
402 '''Set items in batches
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
403
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
404 items is an array of (rev num, branch, binary hash)
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
405
1424
a794cbc174a9 maps: document RevMap.batchset will not update internal state
Jun Wu <quark@fb.com>
parents: 1422
diff changeset
406 For performance reason, internal in-memory state is not updated.
a794cbc174a9 maps: document RevMap.batchset will not update internal state
Jun Wu <quark@fb.com>
parents: 1422
diff changeset
407 To get an up-to-date RevMap, reconstruct the object.
1412
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
408 '''
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
409 with open(self._filepath, 'a') as f:
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
410 f.write(''.join('%s %s %s\n' % (revnum, hex(binhash), br or '')
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
411 for revnum, br, binhash in items))
1455
8cfe074cd463 maps: use util.fileproperty for RevMap.lastpulled
Jun Wu <quark@fb.com>
parents: 1449
diff changeset
412 self.lastpulled = lastpulled
1412
7e98352a37db maps: add the "batchset" method to RevMap
Jun Wu <quark@fb.com>
parents: 1411
diff changeset
413
1421
0094f222c5dc maps: make readmapfile of RevMap a private instance method
Jun Wu <quark@fb.com>
parents: 1419
diff changeset
414 def _readmapfile(self):
1430
48beb467b2e5 RevMap: use self._filepath instead of using meta
Augie Fackler <raf@durin42.com>
parents: 1429
diff changeset
415 path = self._filepath
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
416 try:
1182
8f9619a67565 maps: change readmapfile to take a path instead of repo
Sean Farley <sean.michael.farley@gmail.com>
parents: 1144
diff changeset
417 f = open(path)
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
418 except IOError, err:
1421
0094f222c5dc maps: make readmapfile of RevMap a private instance method
Jun Wu <quark@fb.com>
parents: 1419
diff changeset
419 if err.errno != errno.ENOENT:
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
420 raise
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
421 return iter([])
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
422 ver = int(f.readline())
1469
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
423 if ver == SqliteRevMap.VERSION:
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
424 revmap = SqliteRevMap(self._filepath, self._lastpulled_file)
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
425 tmppath = '%s.tmp' % self._filepath
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
426 revmap.exportrevmapv1(tmppath)
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
427 os.rename(tmppath, self._filepath)
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
428 hgutil.unlinkpath(revmap._dbpath)
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
429 hgutil.unlinkpath(revmap._rowcountpath, ignoremissing=True)
1469
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
430 return self._readmapfile()
1421
0094f222c5dc maps: make readmapfile of RevMap a private instance method
Jun Wu <quark@fb.com>
parents: 1419
diff changeset
431 if ver != self.VERSION:
891
83cc6e9e8425 kill all 'print' statements in the extension proper
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 889
diff changeset
432 raise hgutil.Abort('revmap too new -- please upgrade')
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
433 return f
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
434
1251
46cec117dda2 maps.RevMap: disable GC while loading the revmap
Siddharth Agarwal <sid0@fb.com>
parents: 1217
diff changeset
435 @util.gcdisable
889
7a98fbadcae9 revsets: huge speedups for fromsvn and svnrev
Bryan O'Sullivan <bryano@fb.com>
parents: 847
diff changeset
436 def _load(self):
1434
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
437 lastpulled = self.lastpulled
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
438 firstpulled = self.firstpulled
1254
d07ccad28b1a maps.RevMap: avoid O(revs) property lookups on dict
Siddharth Agarwal <sid0@fb.com>
parents: 1253
diff changeset
439 setitem = dict.__setitem__
1421
0094f222c5dc maps: make readmapfile of RevMap a private instance method
Jun Wu <quark@fb.com>
parents: 1419
diff changeset
440 for l in self._readmapfile():
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
441 revnum, ha, branch = l.split(' ', 2)
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
442 if branch == '\n':
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
443 branch = None
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
444 else:
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
445 branch = branch[:-1]
415
b17b2969861c svnmeta: move revmap methods, make last_known_revision() more efficient
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 409
diff changeset
446 revnum = int(revnum)
1252
a321afbc3479 maps.RevMap: while loading, read lastpulled and firstpulled once
Siddharth Agarwal <sid0@fb.com>
parents: 1251
diff changeset
447 if revnum > lastpulled or not lastpulled:
a321afbc3479 maps.RevMap: while loading, read lastpulled and firstpulled once
Siddharth Agarwal <sid0@fb.com>
parents: 1251
diff changeset
448 lastpulled = revnum
a321afbc3479 maps.RevMap: while loading, read lastpulled and firstpulled once
Siddharth Agarwal <sid0@fb.com>
parents: 1251
diff changeset
449 if revnum < firstpulled or not firstpulled:
a321afbc3479 maps.RevMap: while loading, read lastpulled and firstpulled once
Siddharth Agarwal <sid0@fb.com>
parents: 1251
diff changeset
450 firstpulled = revnum
1254
d07ccad28b1a maps.RevMap: avoid O(revs) property lookups on dict
Siddharth Agarwal <sid0@fb.com>
parents: 1253
diff changeset
451 setitem(self, (revnum, branch), bin(ha))
1434
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
452 if self.lastpulled != lastpulled:
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
453 self.lastpulled = lastpulled
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
454 self.firstpulled = firstpulled
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
455
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
456 def _write(self):
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
457 with open(self._filepath, 'w') as f:
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
458 f.write('%s\n' % self.VERSION)
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
459
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
460 def __setitem__(self, key, ha):
408
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
461 revnum, branch = key
f137231f9d30 extract the revmap support into a separate dict-like class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 360
diff changeset
462 b = branch or ''
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
463 with open(self._filepath, 'a') as f:
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
464 f.write(str(revnum) + ' ' + hex(ha) + ' ' + b + '\n')
1434
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
465 if revnum > self.lastpulled or not self.lastpulled:
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
466 self.lastpulled = revnum
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
467 if revnum < self.firstpulled or not self.firstpulled:
0a6b3da6d34c RevMap: move lastpulled from SVNMeta down into RevMap
Augie Fackler <raf@durin42.com>
parents: 1432
diff changeset
468 self.firstpulled = revnum
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
469 dict.__setitem__(self, (revnum, branch), ha)
1294
9a722b5246df maps: cache hashes() for the revmap
Mateusz Kwapich <mitrandir@fb.com>
parents: 1254
diff changeset
470 if self._hashes is not None:
9a722b5246df maps: cache hashes() for the revmap
Mateusz Kwapich <mitrandir@fb.com>
parents: 1254
diff changeset
471 self._hashes[ha] = (revnum, branch)
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
472
1468
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
473 @classmethod
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
474 def _wrapitermethods(cls):
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
475 def wrap(orig):
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
476 def wrapper(self, *args, **kwds):
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
477 if not self._allowiter:
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
478 raise NotImplementedError(
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
479 'Iteration methods on RevMap are disabled ' +
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
480 'to avoid performance issues on SqliteRevMap')
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
481 return orig(self, *args, **kwds)
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
482 return wrapper
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
483 methodre = re.compile(r'^_*(?:iter|view)?(?:keys|items|values)?_*$')
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
484 for name in filter(methodre.match, dir(cls)):
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
485 orig = getattr(cls, name)
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
486 setattr(cls, '_orig%s' % name, orig)
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
487 setattr(cls, name, wrap(orig))
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
488
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
489 RevMap._wrapitermethods()
b98ff95b5861 maps: disable iterating methods of RevMap
Jun Wu <quark@fb.com>
parents: 1467
diff changeset
490
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
491
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
492 class SqliteRevMap(collections.MutableMapping):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
493 """RevMap backed by sqlite3.
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
494
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
495 It tries to address performance issues for a very large rev map.
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
496 As such iteration is unavailable for both the map itself and the
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
497 reverse map (self.hashes).
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
498
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
499 It migrates from the old RevMap upon first use. Then it will bump the
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
500 version of revmap so RevMap no longer works. The real database is a
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
501 separated file which has a ".db" suffix.
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
502 """
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
503
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
504 VERSION = 2
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
505
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
506 TABLESCHEMA = [
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
507 '''CREATE TABLE IF NOT EXISTS revmap (
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
508 rev INTEGER NOT NULL,
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
509 branch TEXT NOT NULL DEFAULT '',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
510 hash BLOB NOT NULL)''',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
511 ]
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
512
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
513 INDEXSCHEMA = [
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
514 'CREATE UNIQUE INDEX IF NOT EXISTS revbranch ON revmap (rev,branch);',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
515 'CREATE INDEX IF NOT EXISTS hash ON revmap (hash);',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
516 ]
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
517
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
518 # "bytes" in Python 2 will get truncated at '\0' when storing as sqlite
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
519 # blobs. "buffer" does not have this issue. Python 3 does not have "buffer"
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
520 # but "bytes" won't get truncated.
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
521 sqlblobtype = bytes if sys.version_info >= (3, 0) else buffer
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
522
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
523 class ReverseRevMap(object):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
524 # collections.Mapping is not suitable since we don't want 2/3 of
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
525 # its required interfaces: __iter__, __len__.
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
526 def __init__(self, revmap, cache):
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
527 self.revmap = revmap
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
528 self._cache = cache
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
529
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
530 def get(self, key, default=None):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
531 if key not in self._cache:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
532 result = None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
533 for row in self.revmap._query(
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
534 'SELECT rev, branch FROM revmap WHERE hash=?',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
535 (SqliteRevMap.sqlblobtype(key),)):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
536 result = (row[0], row[1] or None)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
537 break
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
538 self._cache[key] = result
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
539 return self._cache[key] or default
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
540
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
541 def __contains__(self, key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
542 return self.get(key) != None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
543
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
544 def __getitem__(self, key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
545 dummy = self._cache
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
546 item = self.get(key, dummy)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
547 if item == dummy:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
548 raise KeyError(key)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
549 else:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
550 return item
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
551
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
552 def keys(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
553 for row in self.revmap._query('SELECT hash FROM revmap'):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
554 yield bytes(row[0])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
555
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
556 lastpulled = util.fileproperty('_lastpulled', lambda x: x._lastpulledpath,
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
557 default=0, deserializer=int)
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
558 rowcount = util.fileproperty('_rowcount', lambda x: x._rowcountpath,
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
559 default=0, deserializer=int)
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
560
1478
797c7b58a735 maps: add a config option to tweak sqlite
Jun Wu <quark@fb.com>
parents: 1477
diff changeset
561 def __init__(self, revmap_path, lastpulled_path, sqlitepragmas=None):
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
562 self._filepath = revmap_path
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
563 self._dbpath = revmap_path + '.db'
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
564 self._rowcountpath = self._dbpath + '.rowcount'
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
565 self._lastpulledpath = lastpulled_path
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
566
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
567 self._db = None
1478
797c7b58a735 maps: add a config option to tweak sqlite
Jun Wu <quark@fb.com>
parents: 1477
diff changeset
568 self._sqlitepragmas = sqlitepragmas
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
569 self.firstpulled = 0
1476
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
570 self._updatefirstlastpulled()
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
571 # __iter__ is expensive and thus disabled by default
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
572 # it should only be enabled for testing
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
573 self._allowiter = False
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
574 # used by self.hashes(), {hash: (rev, branch)}
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
575 self._hashescache = {}
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
576
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
577 def hashes(self):
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
578 return self.ReverseRevMap(self, self._hashescache)
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
579
1472
cf79525f507c maps: change branchedits to accept revnum directly
Jun Wu <quark@fb.com>
parents: 1470
diff changeset
580 def branchedits(self, branch, revnum):
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
581 return [((r[0], r[1] or None), bytes(r[2])) for r in
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
582 self._query('SELECT rev, branch, hash FROM revmap ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
583 'WHERE rev < ? AND branch = ? ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
584 'ORDER BY rev DESC, branch DESC',
1472
cf79525f507c maps: change branchedits to accept revnum directly
Jun Wu <quark@fb.com>
parents: 1470
diff changeset
585 (revnum, branch or ''))]
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
586
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
587 def branchmaxrevnum(self, branch, maxrev):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
588 for row in self._query('SELECT rev FROM revmap ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
589 'WHERE rev <= ? AND branch = ? ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
590 'ORDER By rev DESC LIMIT 1',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
591 (maxrev, branch or '')):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
592 return row[0]
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
593 return 0
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
594
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
595 @property
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
596 def lasthash(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
597 for row in self._query('SELECT hash FROM revmap ORDER BY rev DESC'):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
598 return bytes(row[0])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
599 return None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
600
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
601 def revhashes(self, revnum):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
602 for row in self._query('SELECT hash FROM revmap WHERE rev = ?',
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
603 (revnum,)):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
604 yield bytes(row[0])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
605
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
606 def clear(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
607 hgutil.unlinkpath(self._filepath, ignoremissing=True)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
608 hgutil.unlinkpath(self._dbpath, ignoremissing=True)
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
609 hgutil.unlinkpath(self._rowcountpath, ignoremissing=True)
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
610 self._db = None
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
611 self._hashescache = {}
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
612 self._firstpull = None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
613 self._lastpull = None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
614
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
615 def batchset(self, items, lastpulled):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
616 with self._transaction():
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
617 self._insert(items)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
618 self.lastpulled = lastpulled
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
619
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
620 def __getitem__(self, key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
621 for row in self._querybykey('SELECT hash', key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
622 return bytes(row[0])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
623 raise KeyError(key)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
624
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
625 def __iter__(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
626 if not self._allowiter:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
627 raise NotImplementedError(
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
628 'SqliteRevMap.__iter__ is not implemented intentionally ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
629 'to avoid performance issues')
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
630 # collect result to avoid nested transaction issues
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
631 rows = []
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
632 for row in self._query('SELECT rev, branch FROM revmap'):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
633 rows.append((row[0], row[1] or None))
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
634 return iter(rows)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
635
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
636 def __len__(self):
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
637 # rowcount is faster than "SELECT COUNT(1)". the latter is not O(1)
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
638 return self.rowcount
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
639
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
640 def __setitem__(self, key, binha):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
641 revnum, branch = key
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
642 with self._transaction():
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
643 self._insert([(revnum, branch, binha)])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
644 if revnum < self.firstpulled or not self.firstpulled:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
645 self.firstpulled = revnum
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
646 if revnum > self.lastpulled or not self.lastpulled:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
647 self.lastpulled = revnum
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
648 if self._hashescache:
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
649 self._hashescache[binha] = key
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
650
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
651 def __delitem__(self, key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
652 for row in self._querybykey('DELETE', key):
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
653 if self.rowcount > 0:
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
654 self.rowcount -= 1
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
655 return
1550
67b28d657f62 sqliterevmap: break ".hashes()" cycle in a safer way
Jun Wu <quark@fb.com>
parents: 1518
diff changeset
656 # For performance reason, self._hashescache is not updated
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
657 raise KeyError(key)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
658
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
659 @contextlib.contextmanager
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
660 def _transaction(self, mode='IMMEDIATE'):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
661 if self._db is None:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
662 self._opendb()
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
663 with self._db as db:
1490
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
664 # wait indefinitely for database lock
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
665 while True:
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
666 try:
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
667 db.execute('BEGIN %s' % mode)
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
668 break
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
669 except sqlite3.OperationalError as ex:
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
670 if str(ex) != 'database is locked':
bc73b80baf98 SqliteRevMap: wait indefinitely for database lock
Jun Wu <quark@fb.com>
parents: 1478
diff changeset
671 raise
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
672 yield db
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
673
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
674 def _query(self, sql, params=()):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
675 with self._transaction() as db:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
676 cur = db.execute(sql, params)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
677 try:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
678 for row in cur:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
679 yield row
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
680 finally:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
681 cur.close()
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
682
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
683 def _querybykey(self, prefix, key):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
684 revnum, branch = key
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
685 return self._query(
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
686 '%s FROM revmap WHERE rev=? AND branch=?'
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
687 % prefix, (revnum, branch or ''))
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
688
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
689 def _insert(self, rows):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
690 # convert to a safe type so '\0' does not truncate the blob
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
691 if rows and type(rows[0][-1]) is not self.sqlblobtype:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
692 rows = [(r, b, self.sqlblobtype(h)) for r, b, h in rows]
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
693 self._db.executemany(
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
694 'INSERT OR REPLACE INTO revmap (rev, branch, hash) ' +
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
695 'VALUES (?, ?, ?)', rows)
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
696 # If REPLACE happens, rowcount can be wrong. But it is only used to
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
697 # calculate how many revisions pulled, and during pull we don't
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
698 # replace rows. So it is fine.
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
699 self.rowcount += len(rows)
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
700
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
701 def _opendb(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
702 '''Open the database and make sure the table is created on demand.'''
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
703 version = None
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
704 try:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
705 version = int(open(self._filepath).read(2))
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
706 except (ValueError, IOError):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
707 pass
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
708 if version and version not in [RevMap.VERSION, self.VERSION]:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
709 raise error.Abort('revmap too new -- please upgrade')
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
710
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
711 if self._db:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
712 self._db.close()
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
713
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
714 # if version mismatch, the database is considered invalid
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
715 if version != self.VERSION:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
716 hgutil.unlinkpath(self._dbpath, ignoremissing=True)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
717
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
718 self._db = sqlite3.connect(self._dbpath)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
719 self._db.text_factory = bytes
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
720
1470
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
721 # cache size affects random accessing (e.g. index building)
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
722 # performance greatly. default is 2MB (2000 KB), we want to have
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
723 # a big enough cache that can hold the entire map.
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
724 cachesize = 2000
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
725 for path, ratio in [(self._filepath, 1.7), (self._dbpath, 1)]:
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
726 if os.path.exists(path):
b6e2bc962536 maps: increase sqlite cache size automatically
Jun Wu <quark@fb.com>
parents: 1469
diff changeset
727 cachesize += os.stat(path).st_size * ratio // 1000
1478
797c7b58a735 maps: add a config option to tweak sqlite
Jun Wu <quark@fb.com>
parents: 1477
diff changeset
728
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
729 # disable auto-commit. everything is inside a transaction
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
730 self._db.isolation_level = 'DEFERRED'
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
731
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
732 with self._transaction('EXCLUSIVE'):
1518
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
733 self._db.execute('PRAGMA cache_size=%d' % (-cachesize))
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
734
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
735 # PRAGMA statements provided by the user
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
736 for pragma in (self._sqlitepragmas or []):
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
737 # drop malicious ones
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
738 if re.match(r'\A\w+=\w+\Z', pragma):
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
739 self._db.execute('PRAGMA %s' % pragma)
09476d758b59 maps: handle sqlite lock error triggered by PRAGMA statements
Jun Wu <quark@fb.com>
parents: 1490
diff changeset
740
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
741 map(self._db.execute, self.TABLESCHEMA)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
742 if version == RevMap.VERSION:
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
743 self.rowcount = 0
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
744 self._importrevmapv1()
1475
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
745 elif not self.rowcount:
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
746 self.rowcount = self._db.execute(
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
747 'SELECT COUNT(1) FROM revmap').fetchone()[0]
ea4d6142c6d9 maps: do not ask sqlite for row count
Jun Wu <quark@fb.com>
parents: 1472
diff changeset
748
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
749 # "bulk insert; then create index" is about 2.4x as fast as
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
750 # "create index; then bulk insert" on a large repo
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
751 map(self._db.execute, self.INDEXSCHEMA)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
752
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
753 # write a dummy rev map file with just the revision number
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
754 if version != self.VERSION:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
755 f = open(self._filepath, 'w')
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
756 f.write('%s\n' % self.VERSION)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
757 f.close()
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
758
1476
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
759 def _updatefirstlastpulled(self):
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
760 sql = 'SELECT rev FROM revmap ORDER BY rev %s LIMIT 1'
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
761 for row in self._query(sql % 'ASC'):
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
762 self.firstpulled = row[0]
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
763 for row in self._query(sql % 'DESC'):
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
764 if row[0] > self.lastpulled:
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
765 self.lastpulled = row[0]
581f72f9478b maps: do not ask sqlite for min(rev), max(rev) together
Jun Wu <quark@fb.com>
parents: 1475
diff changeset
766
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
767 @util.gcdisable
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
768 def _importrevmapv1(self):
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
769 with open(self._filepath, 'r') as f:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
770 # 1st line is version
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
771 assert(int(f.readline())) == RevMap.VERSION
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
772 data = {}
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
773 for line in f:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
774 revnum, ha, branch = line[:-1].split(' ', 2)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
775 # ignore malicious lines
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
776 if len(ha) != 40:
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
777 continue
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
778 data[revnum, branch or None] = bin(ha)
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
779 self._insert([(r, b, h) for (r, b), h in data.iteritems()])
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
780
1469
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
781 @util.gcdisable
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
782 def exportrevmapv1(self, path):
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
783 with open(path, 'w') as f:
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
784 f.write('%s\n' % RevMap.VERSION)
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
785 for row in self._query('SELECT rev, branch, hash FROM revmap'):
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
786 rev, br, ha = row
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
787 f.write('%s %s %s\n' % (rev, hex(ha), br))
7bb2c6ca4d24 maps: implement migration from SqliteRevMap to RevMap
Jun Wu <quark@fb.com>
parents: 1468
diff changeset
788
1467
53e306a6086b maps: implement sqlite revmap
Jun Wu <quark@fb.com>
parents: 1455
diff changeset
789
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
790 class FileMap(object):
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
791
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
792 VERSION = 1
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
793
1447
a6fa4f3aa826 FileMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1446
diff changeset
794 def __init__(self, ui, filepath):
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
795 '''Initialise a new FileMap.
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
796
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
797 The ui argument is used to print diagnostic messages.
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
798
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
799 The path argument is the location of the backing store,
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
800 typically .hg/svn/filemap.
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
801 '''
1447
a6fa4f3aa826 FileMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1446
diff changeset
802 self._filename = filepath
a6fa4f3aa826 FileMap: no longer take a meta
Augie Fackler <raf@durin42.com>
parents: 1446
diff changeset
803 self._ui = ui
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
804 self.include = {}
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
805 self.exclude = {}
1437
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
806 if os.path.isfile(self._filename):
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
807 self._load()
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
808 else:
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
809 self._write()
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
810
1214
2c793092862b maps: load commandline filemap in __init__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1213
diff changeset
811 # append file mapping specified from the commandline
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
812 clmap = util.configpath(self._ui, 'filemap')
1214
2c793092862b maps: load commandline filemap in __init__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1213
diff changeset
813 if clmap:
2c793092862b maps: load commandline filemap in __init__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1213
diff changeset
814 self.load(clmap)
2c793092862b maps: load commandline filemap in __init__
Sean Farley <sean.michael.farley@gmail.com>
parents: 1213
diff changeset
815
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
816 def _rpairs(self, name):
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
817 e = len(name)
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
818 while e != -1:
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
819 yield name[:e], name[e+1:]
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
820 e = name.rfind('/', 0, e)
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
821 yield '.', name
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
822
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
823 def check(self, m, path):
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
824 m = getattr(self, m)
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
825 for pre, _suf in self._rpairs(path):
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
826 if pre in m:
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
827 return m[pre]
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
828 return -1
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
829
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
830 def __contains__(self, path):
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
831 if not len(path):
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
832 return True
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
833 if len(self.include):
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
834 inc = self.check('include', path)
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
835 elif not len(self.exclude):
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
836 return True
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
837 else:
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
838 inc = 0
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
839 if len(self.exclude):
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
840 exc = self.check('exclude', path)
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
841 else:
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
842 exc = -1
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
843 # respect rule order: newer rules override older
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
844 return inc > exc
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
845
822
033b86e0f56d stupid/filemap: disable this since it doesn't currently work
Augie Fackler <durin42@gmail.com>
parents: 821
diff changeset
846 # Needed so empty filemaps are false
033b86e0f56d stupid/filemap: disable this since it doesn't currently work
Augie Fackler <durin42@gmail.com>
parents: 821
diff changeset
847 def __len__(self):
033b86e0f56d stupid/filemap: disable this since it doesn't currently work
Augie Fackler <durin42@gmail.com>
parents: 821
diff changeset
848 return len(self.include) + len(self.exclude)
033b86e0f56d stupid/filemap: disable this since it doesn't currently work
Augie Fackler <durin42@gmail.com>
parents: 821
diff changeset
849
826
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
850 def add(self, fn, m, path):
8794302f3614 maps: s/hash/ha/ and s/map/m/ to avoid hiding Python builtins
Yonggang Luo <luoyonggang@gmail.com>
parents: 822
diff changeset
851 mapping = getattr(self, m)
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
852 if path in mapping:
593
eb16630bceb1 maps: fix a % formatting bug
Augie Fackler <durin42@gmail.com>
parents: 579
diff changeset
853 msg = 'duplicate %s entry in %s: "%s"\n'
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
854 self._ui.status(msg % (m, fn, path))
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
855 return
956
24fbba02cb8f maps: fix filemap loading --verbose message
Patrick Mezard <patrick@mezard.eu>
parents: 891
diff changeset
856 bits = m.rstrip('e'), path
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
857 self._ui.debug('%sing %s\n' % bits)
847
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
858 # respect rule order
0de18c5c2e35 Respect filemap rule order (rules that come first are overridden by rules that come later)
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 846
diff changeset
859 mapping[path] = len(self)
1437
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
860 if fn != self._filename:
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
861 with open(self._filename, 'a') as f:
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
862 f.write(m + ' ' + path + '\n')
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
863
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
864 def load(self, fn):
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
865 self._ui.debug('reading file map from %s\n' % fn)
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
866 with open(fn, 'r') as f:
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
867 self.load_fd(f, fn)
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
868
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
869 def load_fd(self, f, fn):
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
870 for line in f:
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
871 if line.strip() == '' or line.strip()[0] == '#':
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
872 continue
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
873 try:
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
874 cmd, path = line.split(' ', 1)
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
875 cmd = cmd.strip()
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
876 path = path.strip()
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
877 if cmd in ('include', 'exclude'):
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
878 self.add(fn, cmd, path)
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
879 continue
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
880 self._ui.warn('unknown filemap command %s\n' % cmd)
409
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
881 except IndexError:
d4615986e1db extract the filemap support into a separate class
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 408
diff changeset
882 msg = 'ignoring bad line in filemap %s: %s\n'
1428
da272633997f maps: store a direct reference to ui
Augie Fackler <raf@durin42.com>
parents: 1427
diff changeset
883 self._ui.warn(msg % (fn, line.rstrip()))
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
884
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
885 def _load(self):
1437
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
886 self._ui.debug('reading in-repo file map from %s\n' % self._filename)
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
887 with open(self._filename) as f:
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
888 ver = int(f.readline())
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
889 if ver != self.VERSION:
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
890 raise hgutil.Abort('filemap too new -- please upgrade')
1437
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
891 self.load_fd(f, self._filename)
846
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
892
7ca3d1b08d67 Save filemap into .hg/svn/filemap just like other maps
Vitaliy Filippov <vitalif@yourcmc.ru>
parents: 829
diff changeset
893 def _write(self):
1437
43df01d36f22 FileMap: store filename locally
Augie Fackler <raf@durin42.com>
parents: 1435
diff changeset
894 with open(self._filename, 'w') as f:
1435
18a961672a72 maps: switch many file opens to using the with statement
Augie Fackler <raf@durin42.com>
parents: 1434
diff changeset
895 f.write('%s\n' % self.VERSION)
574
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
896
1388
130ced9e371d maps: make branch map inherit from base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1387
diff changeset
897 class BranchMap(BaseMap):
574
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
898 '''Facility for controlled renaming of branch names. Example:
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
899
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
900 oldname = newname
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
901 other = default
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
902
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
903 All changes on the oldname branch will now be on the newname branch; all
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
904 changes on other will now be on default (have no branch name set).
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
905 '''
8e025a6f0db4 add basic branchmap functionality, to rename branches
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 573
diff changeset
906
1391
7a866bca15de maps: make tag map inherit from base map
Sean Farley <sean.michael.farley@gmail.com>
parents: 1390
diff changeset
907 class TagMap(BaseMap):
729
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
908 '''Facility for controlled renaming of tags. Example:
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
909
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
910 oldname = newname
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
911 other =
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
912
809
ab372e38fb6c maps: clean up whitespace
Augie Fackler <durin42@gmail.com>
parents: 742
diff changeset
913 The oldname tag from SVN will be represented as newname in the hg tags;
ab372e38fb6c maps: clean up whitespace
Augie Fackler <durin42@gmail.com>
parents: 742
diff changeset
914 the other tag will not be reflected in the hg repository.
729
467b95348e6a implement tag renames
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 728
diff changeset
915 '''