-
Notifications
You must be signed in to change notification settings - Fork 30
/
fabfile.py
245 lines (190 loc) · 7.53 KB
/
fabfile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
'''
A fabric file to automate creation of a special distribution of
xbmcswift2 for XBMC. This distribution doesn't include docs and tests.
It has a slightly different folder structure and contains some XBMC
specific files.
Usage:
# Create a new release for Dharma
$ fab release:dharma,prepare
# Edit the changelog.txt in the temp directory and `git add` it
$ fab release:dharma,perform
'''
import tempfile
import shutil
import os
from xml.etree import ElementTree as ET
import subprocess
import xam
from fabric.api import *
import fabric.colors as colors
EDITOR = 'vim'
REPO_DIR = 'xbmcswift2-xbmc-dist'
REPO_URL = '[email protected]:jbeluch/xbmcswift2-xbmc-dist.git'
REPO_PUBLIC_URL = 'git://github.com/jbeluch/xbmcswift2-xbmc-dist.git'
BRANCHES = {
# <xbmc_version>: <git_branch>
'DHARMA': 'dharma',
'EDEN': 'eden',
'FRODO': 'master',
}
def log(msg, important=False):
if important:
puts(colors.green(msg))
else:
puts(colors.yellow(msg))
class GitRepo(object):
def __init__(self, path=None, remote_url=None):
self.path = path
self.remote_url = remote_url
def clone(self, parent_dir):
with lcd(parent_dir):
local('git clone %s' % self.remote_url)
def stage_all(self):
with lcd(self.path):
local('git add -A')
def get_head_hash(self):
with lcd(self.path):
return local('git log | head -1 | cut -f2 -d" "', capture=True)
def checkout_remote_branch(self, branch):
with lcd(self.path):
if branch == 'master':
local('git checkout master')
else:
local('git checkout -b %s origin/%s' % (branch, branch))
def push(self, branch):
with lcd(self.path):
local('git push --tags origin %s' % branch)
def tag(self, tag, message):
with lcd(self.path):
local('git tag -a %s -m "%s"' % (tag, message))
def commit(self, version):
with lcd(self.path):
local('git commit -m "[xbmcswift2-release-script] prepare release %s"' % version)
def bump_minor(version_str):
left, right = version_str.rsplit('.', 1)
right = int(right) + 1
return '%s.%s' % (left, right)
def get_addon_version(addon_dir):
filename = os.path.join(addon_dir, 'addon.xml')
xml = ET.parse(filename).getroot()
return xam.Addon(xml).version
def get_addon_id(addon_dir):
filename = os.path.join(addon_dir, 'addon.xml')
xml = ET.parse(filename).getroot()
return xam.Addon(xml).id
def set_addon_version(addon_dir, version):
filename = os.path.join(addon_dir, 'addon.xml')
xml = ET.parse(filename).getroot()
addon = xam.Addon(xml)
addon.version = version
write_file(filename, addon.to_xml_string())
def bump_version(addon_dir):
current_version = get_addon_version(addon_dir)
new_version = prompt('Specify new version number: ', default=bump_minor(current_version))
set_addon_version(addon_dir, new_version)
def rmdir(path):
puts('Removing dir %s' % path)
try:
shutil.rmtree(path)
except OSError:
pass
def copydir(src, dest):
puts('Copying %s to %s' % (src, dest))
shutil.copytree(src, dest)
def write_file(path, contents):
puts('Writing content to %s' % path)
with open(path, 'w') as out:
out.write(contents)
def print_email(addon_id, version, git_url, tag, xbmc_version):
lines = [
'Mailing List Email',
'------------------',
'',
'Subject: [git pull] %s' % addon_id,
'*addon - %s' % addon_id,
'*version - %s' % version,
'*url - %s' % git_url,
'*tag - %s' % tag,
'*xbmc version - %s' % xbmc_version,
'',
'',
]
for line in lines:
puts(colors.cyan(line))
@task
def local_release(xbmc_version=None):
if xbmc_version is None:
abort('Must specify an XBMC version, [dharma, eden]')
xbmc_version = xbmc_version.upper()
if xbmc_version not in BRANCHES.keys():
abort('Invalid XBMC version, [dharma, eden]')
local_repo, dist_repo = release_prepare(xbmc_version)
print 'Development release created at %s' % dist_repo.path
@task
def release(xbmc_version=None):
if xbmc_version is None:
abort('Must specify an XBMC version, [dharma, eden]')
xbmc_version = xbmc_version.upper()
if xbmc_version not in BRANCHES.keys():
abort('Invalid XBMC version, [dharma, eden]')
local_repo, dist_repo = release_prepare(xbmc_version)
release_perform(xbmc_version, local_repo, dist_repo)
def release_prepare(xbmc_version):
assert not os.path.exists(os.path.join(os.path.dirname(__file__), '.release')), 'Release in progress. Either `fab release:perform` or `fab release:clear`'
parent_dir = tempfile.mkdtemp()
dist_path = os.path.join(parent_dir, REPO_DIR)
# First get the current git version so we can include this in the release
local_repo = GitRepo(path=os.path.dirname(__file__))
current_git_version = local_repo.get_head_hash()
log('Release using commit %s' % current_git_version)
# Clone a fresh copy of the current dist repo
log('Cloning fresh copy of distribution repo...')
dist_repo = GitRepo(path=dist_path, remote_url=REPO_URL)
dist_repo.clone(parent_dir)
# Checkout the proper branch
log('Using branch %s for the distribution repo...' % BRANCHES[xbmc_version])
dist_repo.checkout_remote_branch(BRANCHES[xbmc_version])
# We could rsync, but easier to just remove existing xbmcswift2 dir and
# copy over the current version
log('Removing old xbmcswift2 dir and copying over current version...')
rmdir(os.path.join(dist_path, 'lib', 'xbmcswift2'))
copydir(os.path.join(local_repo.path, 'xbmcswift2'),
os.path.join(dist_path, 'lib', 'xbmcswift2'))
# Remove the cli and mockxbmc packages as they are not necessary for XBMC
# execution
log('Removing unneccessary cli and mockxbmc packages...')
rmdir(os.path.join(dist_path, 'lib', 'xbmcswift2', 'cli'))
rmdir(os.path.join(dist_path, 'lib', 'xbmcswift2', 'mockxbmc'))
# Now we need to add the current git HEAD to a file in the dist repo
log('Adding deployed git hash to xbmcswift2_version file...')
write_file(os.path.join(dist_path, 'xbmcswift2_version'),
current_git_version)
# Prompt user for new XBMC version
log('Bumping version...')
bump_version(dist_path)
# open changelog in vim
log('Opening changelog.txt for editing...')
changelog = os.path.join(dist_path, 'changelog.txt')
# if user doesn't want to continue they shouldu be able to :cq
returncode = subprocess.check_call([EDITOR, changelog])
# return both repos
return local_repo, GitRepo(path=dist_path)
def release_perform(xbmc_version, local_repo, dist_repo):
# Stage everything in the repo
log('Staging all modified files in the distribution repo...')
dist_repo.stage_all()
# Get the current XBMC version
version = get_addon_version(dist_repo.path)
# Commit all staged changes and tag
log('Commiting changes and tagging the release...')
dist_repo.commit(version)
dist_repo.tag(version, '%s v%s' % (xbmc_version, version))
# Tag the local repo as well
local_repo.tag('xbmc-%s' % version, 'XBMC distribution v%s' % version)
# Push everything
log('Pushing changes to remote...')
dist_repo.push(BRANCHES[xbmc_version])
puts(colors.green('Release performed.'))
# write the email
addon_id = get_addon_id(dist_repo.path)
print_email(addon_id, version, REPO_PUBLIC_URL, version, xbmc_version.lower())