aboutsummaryrefslogtreecommitdiff
blob: a72125d122da4f4db626160d71043f1b074e4efb (plain)
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
# vim: set sw=4 sts=4 et :
# Copyright: 2008 Gentoo Foundation
# Author(s): Nirbheek Chauhan <nirbheek.chauhan@gmail.com>
# License: GPL-2
#
# Immortal lh!
#

import os, subprocess, shutil
import os.path as osp
from .. import const

class Syncer(object):
    """
    Sync stuff
    """

    def __init__(self, scheme='git', uri=const.JOBTAGE_URI, rev=None, destdir=const.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
        @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 1 (init)
         2. Different init & sync commands (eg: git)
            - Detect if self.destdir is a repo
              * Return 2 if it is (sync), 3 if not (rmtree && init)
         3. No concept of sync (eg: bzr-export)
            - Delete self.destdir before 'sync'
              * return 3 (rmtree && init)
        """
        if self.scheme in ['rsync']:
            return 1
        elif self.scheme in ['git', 'bzr']:
            result = subprocess.Popen('cd %s; git-rev-parse' % self.destdir, shell=True)
            if result != 0:
                return 3
            return 2
        elif self.scheme in ['git-export', 'bzr-export']:
            return 3

    def sync(self):
        """
        Sync self.uri contents to self.destdir 
        """
        if osp.exists(self.destdir):
            if not osp.isdir(self.destdir):
                # FIXME: Custom exceptions
                raise '"%s" exists and is not a directory' % self.destdir
            result = self._is_repo()
            if result == '1':
                self.command.run('init')
            elif result == '2':
                self.command.run('sync')
            elif result == '3':
                raise 'destdir: \"%s\" exists and is not a %s tree' % self.destdir, self.scheme
        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':
            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':
            if action == 'init':
                return 'git clone "%s" "%s"' % (self.uri, self.destdir)
            if action == 'sync':
                return 'cd "%s"; git reset --hard HEAD; git pull "%s"' % (self.destdir, self.uri)
        elif self.scheme == 'git-export':
            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':
            command = 'rsync -a --delete "%s" "%s"' % (self.uri, self.destdir)
            if const.VERBOSE:
                command += ' --verbose'
            return command
        raise "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)