/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/generate_ids.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007, 2009, 2010, 2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Common code for generating file or revision ids."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
 
23
import time
 
24
 
 
25
from bzrlib import (
 
26
    config,
 
27
    errors,
 
28
    osutils,
 
29
    )
 
30
""")
 
31
 
 
32
from bzrlib import (
 
33
    lazy_regex,
 
34
    )
 
35
 
 
36
# the regex removes any weird characters; we don't escape them
 
37
# but rather just pull them out
 
38
_file_id_chars_re = lazy_regex.lazy_compile(r'[^\w.]')
 
39
_rev_id_chars_re = lazy_regex.lazy_compile(r'[^-\w.+@]')
 
40
_gen_file_id_suffix = None
 
41
_gen_file_id_serial = 0
 
42
 
 
43
 
 
44
def _next_id_suffix():
 
45
    """Create a new file id suffix that is reasonably unique.
 
46
 
 
47
    On the first call we combine the current time with 64 bits of randomness to
 
48
    give a highly probably globally unique number. Then each call in the same
 
49
    process adds 1 to a serial number we append to that unique value.
 
50
    """
 
51
    # XXX TODO: change bzrlib.add.smart_add_tree to call workingtree.add() rather
 
52
    # than having to move the id randomness out of the inner loop like this.
 
53
    # XXX TODO: for the global randomness this uses we should add the thread-id
 
54
    # before the serial #.
 
55
    # XXX TODO: jam 20061102 I think it would be good to reset every 100 or
 
56
    #           1000 calls, or perhaps if time.time() increases by a certain
 
57
    #           amount. time.time() shouldn't be terribly expensive to call,
 
58
    #           and it means that long-lived processes wouldn't use the same
 
59
    #           suffix forever.
 
60
    global _gen_file_id_suffix, _gen_file_id_serial
 
61
    if _gen_file_id_suffix is None:
 
62
        _gen_file_id_suffix = "-%s-%s-" % (osutils.compact_date(time.time()),
 
63
                                           osutils.rand_chars(16))
 
64
    _gen_file_id_serial += 1
 
65
    return _gen_file_id_suffix + str(_gen_file_id_serial)
 
66
 
 
67
 
 
68
def gen_file_id(name):
 
69
    """Return new file id for the basename 'name'.
 
70
 
 
71
    The uniqueness is supplied from _next_id_suffix.
 
72
    """
 
73
    # The real randomness is in the _next_id_suffix, the
 
74
    # rest of the identifier is just to be nice.
 
75
    # So we:
 
76
    # 1) Remove non-ascii word characters to keep the ids portable
 
77
    # 2) squash to lowercase, so the file id doesn't have to
 
78
    #    be escaped (case insensitive filesystems would bork for ids
 
79
    #    that only differ in case without escaping).
 
80
    # 3) truncate the filename to 20 chars. Long filenames also bork on some
 
81
    #    filesystems
 
82
    # 4) Removing starting '.' characters to prevent the file ids from
 
83
    #    being considered hidden.
 
84
    ascii_word_only = str(_file_id_chars_re.sub('', name.lower()))
 
85
    short_no_dots = ascii_word_only.lstrip('.')[:20]
 
86
    return short_no_dots + _next_id_suffix()
 
87
 
 
88
 
 
89
def gen_root_id():
 
90
    """Return a new tree-root file id."""
 
91
    return gen_file_id('tree_root')
 
92
 
 
93
 
 
94
def gen_revision_id(username, timestamp=None):
 
95
    """Return new revision-id.
 
96
 
 
97
    :param username: The username of the committer, in the format returned by
 
98
        config.username().  This is typically a real name, followed by an
 
99
        email address. If found, we will use just the email address portion.
 
100
        Otherwise we flatten the real name, and use that.
 
101
    :return: A new revision id.
 
102
    """
 
103
    try:
 
104
        user_or_email = config.extract_email_address(username)
 
105
    except errors.NoEmailInUsername:
 
106
        user_or_email = username
 
107
 
 
108
    user_or_email = user_or_email.lower()
 
109
    user_or_email = user_or_email.replace(' ', '_')
 
110
    user_or_email = _rev_id_chars_re.sub('', user_or_email)
 
111
 
 
112
    # This gives 36^16 ~= 2^82.7 ~= 83 bits of entropy
 
113
    unique_chunk = osutils.rand_chars(16)
 
114
 
 
115
    if timestamp is None:
 
116
        timestamp = time.time()
 
117
 
 
118
    rev_id = u'-'.join((user_or_email,
 
119
                        osutils.compact_date(timestamp),
 
120
                        unique_chunk))
 
121
    return rev_id.encode('utf8')