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
|
# vim: set sw=4 sts=4 et :
# Copyright: 2008 Gentoo Foundation
# Author(s): Nirbheek Chauhan <nirbheek.chauhan@gmail.com>
# License: GPL-3
#
# Immortal lh!
#
import os, subprocess, shutil
import os.path as osp
from .. import config
# init == sync (example: rsync)
ONLY_SYNC = 1
# init and sync are different (eg: git)
INIT_SYNC = 2
# sync == rmtree && init (eg: bzr-export, git with destdir not a repo)
RMTREE_INIT = 3
class Syncer(object):
"""
Sync stuff
"""
def __init__(self, scheme='git', uri=config.JOBTAGE_URI, rev=None, destdir=config.JOBTAGE_DIR):
"""
Default is to sync the jobtage tree from the default location.
@param destdir: Destination directory; sync *contents* into destdir
@scheme destdir: string
@param uri: Uri where to sync from
@scheme uri: string
@param rev: SCM Revision to export. Default is latest
this variable is only taken into account in
the following cases: bzr-export, git-export
@scheme rev: string
@param scheme: The URI scheme
@scheme scheme: string
"""
self.destdir = destdir
self.scheme = scheme
self.command = Command(scheme, uri, rev, destdir)
def _is_repo(self):
"""
Broad classification of repos into three types based on their behaviour
1. Same commands for init & sync (eg: rsync)
- return ONLY_SYNC
2. Different init & sync commands (eg: git)
- Detect if self.destdir is a repo
* Return INIT_SYNC if it is, RMTREE_INIT if not (rmtree && init)
3. No concept of sync (eg: bzr-export)
- Delete self.destdir before 'sync'
* return RMTREE_INIT (rmtree && init)
"""
if self.scheme in ['rsync', 'rsync-nc']:
return ONLY_SYNC
elif self.scheme in ['git', 'bzr']:
is_repo_cmd = None
if self.scheme == 'git':
is_repo_cmd = 'git rev-parse'
elif self.scheme == 'bzr':
is_repo_cmd = 'bzr info'
else:
raise Exception('Unknown scm: "%s"' % self.scheme)
result = subprocess.Popen('cd "%s"; %s' % (self.destdir, is_repo_cmd), shell=True)
returncode = result.wait()
if returncode != 0:
return RMTREE_INIT
return INIT_SYNC
elif self.scheme in ['git-export', 'bzr-export']:
return RMTREE_INIT
def sync(self):
"""
Sync self.uri contents to self.destdir
"""
if osp.exists(self.destdir):
if not osp.isdir(self.destdir):
raise Exception('"%s" exists and is not a directory' % self.destdir)
result = self._is_repo()
if result == ONLY_SYNC:
self.command.run('init')
elif result == INIT_SYNC:
self.command.run('sync')
elif result == RMTREE_INIT:
shutil.rmtree(self.destdir)
self.command.run('init')
else:
raise Exception('Erm. I did not expect this. DIE DIE DIE.')
else:
if not osp.exists(osp.dirname(self.destdir)):
# Create parents
os.makedirs(osp.dirname(self.destdir))
self.command.run('init')
class Command(object):
"""Command to use for each uri scheme and action"""
def __init__(self, scheme, uri, rev, destdir):
if not uri.endswith('/'):
uri += '/'
if not rev:
if scheme == 'bzr-export':
rev = 'last:1'
elif scheme == 'git-export':
rev = 'HEAD'
self.scheme = scheme
self.uri = uri
self.rev = rev
self.destdir = destdir
def _get_args(self, action='init'):
if self.scheme == 'bzr': # Sync to latest revision
if action == 'init':
return 'bzr branch "%s" "%s"' % (self.uri, self.destdir)
elif action == 'sync':
return 'bzr pull --overwrite "%s" -d "%s"' % (self.uri, self.destdir)
elif self.scheme == 'bzr-export':
return 'bzr export -r"%s" "%s" "%s"' % (self.rev, self.destdir, self.uri)
elif self.scheme == 'git': # Sync to latest HEAD
cmd = 'export GIT_DIR="%s" URI="%s";' % (self.destdir, self.uri)
if action == 'init':
return cmd+'git clone --bare "$URI" "$GIT_DIR";git config remote.origin.url "$URI"'
if action == 'sync':
return cmd+'git config remote.origin.url "$URI";git fetch -f -u origin master:master'
elif self.scheme == 'git-export': # export self.rev
return 'git archive --prefix="%s/" --remote="%s" "%s" | tar x -C "%s"' % \
(osp.basename(self.destdir), self.uri, self.rev, osp.dirname(self.destdir))
elif self.scheme == 'rsync': # rsync, delete
return 'rsync -a --delete-after "%s" "%s"' % (self.uri, self.destdir)
elif self.scheme == 'rsync-nc': # rsync, no-clobber
return 'rsync -a "%s" "%s"' % (self.uri, self.destdir)
else:
raise Exception("Unknown scheme: %s" % self.scheme)
def run(self, action):
"""Run a sync command"""
args = self._get_args(action=action)
subprocess.check_call(args, shell=True)
if __name__ == "__main__":
syncer = Syncer(destdir='/tmp/jobtage')
syncer.sync()
|