Merge branch 'stable'
[stgit] / stgit / lib / stackupgrade.py
1 import os.path
2 from stgit import utils
3 from stgit.out import out
4 from stgit.config import config
5
6 # The current StGit metadata format version.
7 FORMAT_VERSION = 2
8
9 def format_version_key(branch):
10 return 'branch.%s.stgit.stackformatversion' % branch
11
12 def update_to_current_format_version(repository, branch):
13 """Update a potentially older StGit directory structure to the latest
14 version. Note: This function should depend as little as possible
15 on external functions that may change during a format version
16 bump, since it must remain able to process older formats."""
17
18 branch_dir = os.path.join(repository.directory, 'patches', branch)
19 key = format_version_key(branch)
20 old_key = 'branch.%s.stgitformatversion' % branch
21 def get_format_version():
22 """Return the integer format version number, or None if the
23 branch doesn't have any StGit metadata at all, of any version."""
24 fv = config.get(key)
25 ofv = config.get(old_key)
26 if fv:
27 # Great, there's an explicitly recorded format version
28 # number, which means that the branch is initialized and
29 # of that exact version.
30 return int(fv)
31 elif ofv:
32 # Old name for the version info: upgrade it.
33 config.set(key, ofv)
34 config.unset(old_key)
35 return int(ofv)
36 elif os.path.isdir(os.path.join(branch_dir, 'patches')):
37 # There's a .git/patches/<branch>/patches dirctory, which
38 # means this is an initialized version 1 branch.
39 return 1
40 elif os.path.isdir(branch_dir):
41 # There's a .git/patches/<branch> directory, which means
42 # this is an initialized version 0 branch.
43 return 0
44 else:
45 # The branch doesn't seem to be initialized at all.
46 return None
47 def set_format_version(v):
48 out.info('Upgraded branch %s to format version %d' % (branch, v))
49 config.set(key, '%d' % v)
50 def mkdir(d):
51 if not os.path.isdir(d):
52 os.makedirs(d)
53 def rm(f):
54 if os.path.exists(f):
55 os.remove(f)
56 def rm_ref(ref):
57 if repository.refs.exists(ref):
58 repository.refs.delete(ref)
59
60 # Update 0 -> 1.
61 if get_format_version() == 0:
62 mkdir(os.path.join(branch_dir, 'trash'))
63 patch_dir = os.path.join(branch_dir, 'patches')
64 mkdir(patch_dir)
65 refs_base = 'refs/patches/%s' % branch
66 for patch in (file(os.path.join(branch_dir, 'unapplied')).readlines()
67 + file(os.path.join(branch_dir, 'applied')).readlines()):
68 patch = patch.strip()
69 os.rename(os.path.join(branch_dir, patch),
70 os.path.join(patch_dir, patch))
71 topfield = os.path.join(patch_dir, patch, 'top')
72 if os.path.isfile(topfield):
73 top = utils.read_string(topfield, False)
74 else:
75 top = None
76 if top:
77 repository.refs.set(refs_base + '/' + patch,
78 repository.get_commit(top), 'StGit upgrade')
79 set_format_version(1)
80
81 # Update 1 -> 2.
82 if get_format_version() == 1:
83 desc_file = os.path.join(branch_dir, 'description')
84 if os.path.isfile(desc_file):
85 desc = utils.read_string(desc_file)
86 if desc:
87 config.set('branch.%s.description' % branch, desc)
88 rm(desc_file)
89 rm(os.path.join(branch_dir, 'current'))
90 rm_ref('refs/bases/%s' % branch)
91 set_format_version(2)
92
93 # compatibility with the new infrastructure. The changes here do not
94 # affect the compatibility with the old infrastructure (format version 2)
95 if get_format_version() == 2:
96 hidden_file = os.path.join(branch_dir, 'hidden')
97 if not os.path.isfile(hidden_file):
98 utils.create_empty_file(hidden_file)
99
100 # Make sure we're at the latest version.
101 fv = get_format_version()
102 if not fv in [None, FORMAT_VERSION]:
103 raise StackException('Branch %s is at format version %d, expected %d'
104 % (branch, fv, FORMAT_VERSION))
105 return fv != None # true if branch is initialized