blob: 91c5d5808642804aa33896966284214e89aea975 [file] [log] [blame]
Caroline Ticef6ef4392017-04-06 17:16:05 -07001#!/usr/bin/env python2
asharifec9c6242013-02-15 19:56:06 +00002#
3# Copyright 2010 Google Inc. All Rights Reserved.
Caroline Tice88272d42016-01-13 09:48:29 -08004"""Module for transferring files between various types of repositories."""
5
6from __future__ import print_function
asharifec9c6242013-02-15 19:56:06 +00007
asharif0ea89582013-02-15 21:15:11 +00008__author__ = 'asharif@google.com (Ahmad Sharif)'
asharifec9c6242013-02-15 19:56:06 +00009
Caroline Tice88272d42016-01-13 09:48:29 -080010import argparse
Han Sheneb77c442013-03-18 13:53:52 -070011import datetime
Caroline Tice88272d42016-01-13 09:48:29 -080012import json
asharifec9c6242013-02-15 19:56:06 +000013import os
14import re
15import socket
16import sys
17import tempfile
kbaclawski20082a02013-02-16 02:12:57 +000018
asharif0ea89582013-02-15 21:15:11 +000019from automation.clients.helper import perforce
Caroline Ticea8af9a72016-07-20 12:52:59 -070020from cros_utils import command_executer
21from cros_utils import logger
22from cros_utils import misc
asharifec9c6242013-02-15 19:56:06 +000023
Caroline Tice88272d42016-01-13 09:48:29 -080024# pylint: disable=anomalous-backslash-in-string
asharifec9c6242013-02-15 19:56:06 +000025
Caroline Ticef6ef4392017-04-06 17:16:05 -070026
asharif1b92e732013-02-15 20:51:38 +000027def GetCanonicalMappings(mappings):
28 canonical_mappings = []
29 for mapping in mappings:
30 remote_path, local_path = mapping.split()
asharif0ea89582013-02-15 21:15:11 +000031 if local_path.endswith('/') and not remote_path.endswith('/'):
asharif1b92e732013-02-15 20:51:38 +000032 local_path = os.path.join(local_path, os.path.basename(remote_path))
33 remote_path = remote_path.lstrip('/').split('/', 1)[1]
34 canonical_mappings.append(perforce.PathMapping(remote_path, local_path))
35 return canonical_mappings
36
asharif0ea89582013-02-15 21:15:11 +000037
asharif56d78bc2013-02-15 21:15:08 +000038def SplitMapping(mapping):
asharif0ea89582013-02-15 21:15:11 +000039 parts = mapping.split()
40 assert len(parts) <= 2, 'Mapping %s invalid' % mapping
41 remote_path = parts[0]
42 if len(parts) == 2:
43 local_path = parts[1]
asharif56d78bc2013-02-15 21:15:08 +000044 else:
asharif0ea89582013-02-15 21:15:11 +000045 local_path = '.'
asharif56d78bc2013-02-15 21:15:08 +000046 return remote_path, local_path
47
asharif1b92e732013-02-15 20:51:38 +000048
49class Repo(object):
Caroline Tice88272d42016-01-13 09:48:29 -080050 """Basic repository base class."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -080051
Han Sheneb77c442013-03-18 13:53:52 -070052 def __init__(self, no_create_tmp_dir=False):
asharifec9c6242013-02-15 19:56:06 +000053 self.repo_type = None
54 self.address = None
55 self.mappings = None
56 self.revision = None
asharif0ea89582013-02-15 21:15:11 +000057 self.ignores = ['.gitignore', '.p4config', 'README.google']
Han Sheneb77c442013-03-18 13:53:52 -070058 if no_create_tmp_dir:
59 self._root_dir = None
60 else:
61 self._root_dir = tempfile.mkdtemp()
asharif56d78bc2013-02-15 21:15:08 +000062 self._ce = command_executer.GetCommandExecuter()
63 self._logger = logger.GetLogger()
asharifec9c6242013-02-15 19:56:06 +000064
asharif56d78bc2013-02-15 21:15:08 +000065 def PullSources(self):
asharif0ea89582013-02-15 21:15:11 +000066 """Pull all sources into an internal dir."""
asharifec9c6242013-02-15 19:56:06 +000067 pass
68
asharif56d78bc2013-02-15 21:15:08 +000069 def SetupForPush(self):
asharif0ea89582013-02-15 21:15:11 +000070 """Setup a repository for pushing later."""
asharif56d78bc2013-02-15 21:15:08 +000071 pass
72
asharif983c7c42013-02-16 02:13:01 +000073 def PushSources(self, commit_message=None, dry_run=False, message_file=None):
asharif0ea89582013-02-15 21:15:11 +000074 """Push to the external repo with the commit message."""
asharif56d78bc2013-02-15 21:15:08 +000075 pass
76
77 def _RsyncExcludingRepoDirs(self, source_dir, dest_dir):
ashariff6ffe502013-02-15 22:23:12 +000078 for f in os.listdir(source_dir):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080079 if f in ['.git', '.svn', '.p4config']:
ashariff6ffe502013-02-15 22:23:12 +000080 continue
81 dest_file = os.path.join(dest_dir, f)
82 source_file = os.path.join(source_dir, f)
83 if os.path.exists(dest_file):
Luis Lozanof2a3ef42015-12-15 13:49:30 -080084 command = 'rm -rf %s' % dest_file
ashariff6ffe502013-02-15 22:23:12 +000085 self._ce.RunCommand(command)
Luis Lozanof2a3ef42015-12-15 13:49:30 -080086 command = 'rsync -a %s %s' % (source_file, dest_dir)
ashariff6ffe502013-02-15 22:23:12 +000087 self._ce.RunCommand(command)
88 return 0
asharif56d78bc2013-02-15 21:15:08 +000089
90 def MapSources(self, dest_dir):
91 """Copy sources from the internal dir to root_dir."""
92 return self._RsyncExcludingRepoDirs(self._root_dir, dest_dir)
93
94 def GetRoot(self):
95 return self._root_dir
96
Caroline Tice88272d42016-01-13 09:48:29 -080097 def SetRoot(self, directory):
98 self._root_dir = directory
99
asharif56d78bc2013-02-15 21:15:08 +0000100 def CleanupRoot(self):
asharif0ea89582013-02-15 21:15:11 +0000101 command = 'rm -rf %s' % self._root_dir
asharif56d78bc2013-02-15 21:15:08 +0000102 return self._ce.RunCommand(command)
asharifec9c6242013-02-15 19:56:06 +0000103
104 def __str__(self):
Caroline Ticef6ef4392017-04-06 17:16:05 -0700105 return '\n'.join(
106 str(s) for s in [self.repo_type, self.address, self.mappings])
asharifec9c6242013-02-15 19:56:06 +0000107
108
Han Sheneb77c442013-03-18 13:53:52 -0700109# Note - this type of repo is used only for "readonly", in other words, this
110# only serves as a incoming repo.
111class FileRepo(Repo):
Caroline Tice88272d42016-01-13 09:48:29 -0800112 """Class for file repositories."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800113
Han Sheneb77c442013-03-18 13:53:52 -0700114 def __init__(self, address, ignores=None):
115 Repo.__init__(self, no_create_tmp_dir=True)
116 self.repo_type = 'file'
117 self.address = address
118 self.mappings = None
119 self.branch = None
120 self.revision = '{0} (as of "{1}")'.format(address, datetime.datetime.now())
121 self.gerrit = None
122 self._root_dir = self.address
Caroline Tice88272d42016-01-13 09:48:29 -0800123 if ignores:
124 self.ignores += ignores
Han Sheneb77c442013-03-18 13:53:52 -0700125
126 def CleanupRoot(self):
127 """Override to prevent deletion."""
128 pass
129
130
asharifec9c6242013-02-15 19:56:06 +0000131class P4Repo(Repo):
Caroline Tice88272d42016-01-13 09:48:29 -0800132 """Class for P4 repositories."""
133
asharif6578cf82013-02-16 02:41:46 +0000134 def __init__(self, address, mappings, revision=None):
asharifec9c6242013-02-15 19:56:06 +0000135 Repo.__init__(self)
asharif0ea89582013-02-15 21:15:11 +0000136 self.repo_type = 'p4'
asharifec9c6242013-02-15 19:56:06 +0000137 self.address = address
138 self.mappings = mappings
asharif6578cf82013-02-16 02:41:46 +0000139 self.revision = revision
asharifec9c6242013-02-15 19:56:06 +0000140
asharif56d78bc2013-02-15 21:15:08 +0000141 def PullSources(self):
asharifec9c6242013-02-15 19:56:06 +0000142 client_name = socket.gethostname()
asharif0ea89582013-02-15 21:15:11 +0000143 client_name += tempfile.mkstemp()[1].replace('/', '-')
asharifec9c6242013-02-15 19:56:06 +0000144 mappings = self.mappings
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800145 p4view = perforce.View('depot2', GetCanonicalMappings(mappings))
Caroline Ticef6ef4392017-04-06 17:16:05 -0700146 p4client = perforce.CommandsFactory(
147 self._root_dir, p4view, name=client_name)
asharif6578cf82013-02-16 02:41:46 +0000148 command = p4client.SetupAndDo(p4client.Sync(self.revision))
asharif0ea89582013-02-15 21:15:11 +0000149 ret = self._ce.RunCommand(command)
150 assert ret == 0, 'Could not setup client.'
asharif1b92e732013-02-15 20:51:38 +0000151 command = p4client.InCheckoutDir(p4client.SaveCurrentCLNumber())
Luis Lozano036c9232015-12-10 10:47:01 -0800152 ret, o, _ = self._ce.RunCommandWOutput(command)
asharif0ea89582013-02-15 21:15:11 +0000153 assert ret == 0, 'Could not get version from client.'
154 self.revision = re.search('^\d+$', o.strip(), re.MULTILINE).group(0)
asharif1b92e732013-02-15 20:51:38 +0000155 command = p4client.InCheckoutDir(p4client.Remove())
asharif0ea89582013-02-15 21:15:11 +0000156 ret = self._ce.RunCommand(command)
157 assert ret == 0, 'Could not delete client.'
asharif1b92e732013-02-15 20:51:38 +0000158 return 0
asharifec9c6242013-02-15 19:56:06 +0000159
160
161class SvnRepo(Repo):
Caroline Tice88272d42016-01-13 09:48:29 -0800162 """Class for svn repositories."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800163
asharifec9c6242013-02-15 19:56:06 +0000164 def __init__(self, address, mappings):
165 Repo.__init__(self)
asharif0ea89582013-02-15 21:15:11 +0000166 self.repo_type = 'svn'
asharifec9c6242013-02-15 19:56:06 +0000167 self.address = address
168 self.mappings = mappings
169
asharif56d78bc2013-02-15 21:15:08 +0000170 def PullSources(self):
kbaclawski20082a02013-02-16 02:12:57 +0000171 with misc.WorkingDirectory(self._root_dir):
asharif56d78bc2013-02-15 21:15:08 +0000172 for mapping in self.mappings:
173 remote_path, local_path = SplitMapping(mapping)
asharif0ea89582013-02-15 21:15:11 +0000174 command = 'svn co %s/%s %s' % (self.address, remote_path, local_path)
asharif56d78bc2013-02-15 21:15:08 +0000175 ret = self._ce.RunCommand(command)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800176 if ret:
177 return ret
asharif56d78bc2013-02-15 21:15:08 +0000178
asharif0ea89582013-02-15 21:15:11 +0000179 self.revision = ''
asharif56d78bc2013-02-15 21:15:08 +0000180 for mapping in self.mappings:
181 remote_path, local_path = SplitMapping(mapping)
asharif39f7cb22013-02-19 19:35:16 +0000182 command = 'cd %s && svnversion -c .' % (local_path)
Luis Lozano036c9232015-12-10 10:47:01 -0800183 ret, o, _ = self._ce.RunCommandWOutput(command)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800184 self.revision += o.strip().split(':')[-1]
185 if ret:
186 return ret
asharifcdbacaf2013-02-15 20:09:23 +0000187 return 0
asharifec9c6242013-02-15 19:56:06 +0000188
189
190class GitRepo(Repo):
Caroline Tice88272d42016-01-13 09:48:29 -0800191 """Class for git repositories."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800192
asharif2aeeaca2013-02-16 02:11:04 +0000193 def __init__(self, address, branch, mappings=None, ignores=None, gerrit=None):
asharifec9c6242013-02-15 19:56:06 +0000194 Repo.__init__(self)
asharif0ea89582013-02-15 21:15:11 +0000195 self.repo_type = 'git'
asharifec9c6242013-02-15 19:56:06 +0000196 self.address = address
asharif0ea89582013-02-15 21:15:11 +0000197 self.branch = branch or 'master'
asharifec9c6242013-02-15 19:56:06 +0000198 if ignores:
199 self.ignores += ignores
asharif56d78bc2013-02-15 21:15:08 +0000200 self.mappings = mappings
asharif2aeeaca2013-02-16 02:11:04 +0000201 self.gerrit = gerrit
asharifec9c6242013-02-15 19:56:06 +0000202
asharif56d78bc2013-02-15 21:15:08 +0000203 def _CloneSources(self):
kbaclawski20082a02013-02-16 02:12:57 +0000204 with misc.WorkingDirectory(self._root_dir):
asharif0ea89582013-02-15 21:15:11 +0000205 command = 'git clone %s .' % (self.address)
asharif56d78bc2013-02-15 21:15:08 +0000206 return self._ce.RunCommand(command)
asharifec9c6242013-02-15 19:56:06 +0000207
asharif56d78bc2013-02-15 21:15:08 +0000208 def PullSources(self):
kbaclawski20082a02013-02-16 02:12:57 +0000209 with misc.WorkingDirectory(self._root_dir):
asharif0ea89582013-02-15 21:15:11 +0000210 ret = self._CloneSources()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800211 if ret:
212 return ret
asharifec9c6242013-02-15 19:56:06 +0000213
asharif0ea89582013-02-15 21:15:11 +0000214 command = 'git checkout %s' % self.branch
asharif56d78bc2013-02-15 21:15:08 +0000215 ret = self._ce.RunCommand(command)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800216 if ret:
217 return ret
asharifec9c6242013-02-15 19:56:06 +0000218
asharif0ea89582013-02-15 21:15:11 +0000219 command = 'git describe --always'
Luis Lozano036c9232015-12-10 10:47:01 -0800220 ret, o, _ = self._ce.RunCommandWOutput(command)
asharif56d78bc2013-02-15 21:15:08 +0000221 self.revision = o.strip()
222 return ret
asharifec9c6242013-02-15 19:56:06 +0000223
asharif56d78bc2013-02-15 21:15:08 +0000224 def SetupForPush(self):
kbaclawski20082a02013-02-16 02:12:57 +0000225 with misc.WorkingDirectory(self._root_dir):
asharif56d78bc2013-02-15 21:15:08 +0000226 ret = self._CloneSources()
Caroline Ticef6ef4392017-04-06 17:16:05 -0700227 logger.GetLogger().LogFatalIf(
228 ret, 'Could not clone git repo %s.' % self.address)
asharifec9c6242013-02-15 19:56:06 +0000229
asharif0ea89582013-02-15 21:15:11 +0000230 command = 'git branch -a | grep -wq %s' % self.branch
asharif56d78bc2013-02-15 21:15:08 +0000231 ret = self._ce.RunCommand(command)
asharifec9c6242013-02-15 19:56:06 +0000232
asharif56d78bc2013-02-15 21:15:08 +0000233 if ret == 0:
asharif0ea89582013-02-15 21:15:11 +0000234 if self.branch != 'master':
Caroline Ticef6ef4392017-04-06 17:16:05 -0700235 command = ('git branch --track %s remotes/origin/%s' % (self.branch,
236 self.branch))
asharif56d78bc2013-02-15 21:15:08 +0000237 else:
asharif0ea89582013-02-15 21:15:11 +0000238 command = 'pwd'
239 command += '&& git checkout %s' % self.branch
asharif56d78bc2013-02-15 21:15:08 +0000240 else:
asharif0ea89582013-02-15 21:15:11 +0000241 command = 'git symbolic-ref HEAD refs/heads/%s' % self.branch
242 command += '&& rm -rf *'
asharif56d78bc2013-02-15 21:15:08 +0000243 ret = self._ce.RunCommand(command)
244 return ret
245
Han Sheneb77c442013-03-18 13:53:52 -0700246 def CommitLocally(self, commit_message=None, message_file=None):
kbaclawski20082a02013-02-16 02:12:57 +0000247 with misc.WorkingDirectory(self._root_dir):
asharif0ea89582013-02-15 21:15:11 +0000248 command = 'pwd'
249 for ignore in self.ignores:
250 command += '&& echo \'%s\' >> .git/info/exclude' % ignore
251 command += '&& git add -Av .'
asharif983c7c42013-02-16 02:13:01 +0000252 if message_file:
253 message_arg = '-F %s' % message_file
254 elif commit_message:
255 message_arg = '-m \'%s\'' % commit_message
256 else:
Caroline Tice9099a782016-07-22 16:28:12 -0700257 raise RuntimeError('No commit message given!')
asharif983c7c42013-02-16 02:13:01 +0000258 command += '&& git commit -v %s' % message_arg
Han Sheneb77c442013-03-18 13:53:52 -0700259 return self._ce.RunCommand(command)
260
261 def PushSources(self, commit_message=None, dry_run=False, message_file=None):
262 ret = self.CommitLocally(commit_message, message_file)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800263 if ret:
264 return ret
Han Sheneb77c442013-03-18 13:53:52 -0700265 push_args = ''
266 if dry_run:
267 push_args += ' -n '
268 with misc.WorkingDirectory(self._root_dir):
asharif2aeeaca2013-02-16 02:11:04 +0000269 if self.gerrit:
270 label = 'somelabel'
271 command = 'git remote add %s %s' % (label, self.address)
Caroline Ticef6ef4392017-04-06 17:16:05 -0700272 command += ('&& git push %s %s HEAD:refs/for/master' % (push_args,
273 label))
asharif2aeeaca2013-02-16 02:11:04 +0000274 else:
275 command = 'git push -v %s origin %s:%s' % (push_args, self.branch,
276 self.branch)
277 ret = self._ce.RunCommand(command)
Han Sheneb77c442013-03-18 13:53:52 -0700278 return ret
asharif56d78bc2013-02-15 21:15:08 +0000279
280 def MapSources(self, root_dir):
281 if not self.mappings:
ashariff6ffe502013-02-15 22:23:12 +0000282 self._RsyncExcludingRepoDirs(self._root_dir, root_dir)
asharif56d78bc2013-02-15 21:15:08 +0000283 return
kbaclawski20082a02013-02-16 02:12:57 +0000284 with misc.WorkingDirectory(self._root_dir):
asharif56d78bc2013-02-15 21:15:08 +0000285 for mapping in self.mappings:
286 remote_path, local_path = SplitMapping(mapping)
asharif0ea89582013-02-15 21:15:11 +0000287 remote_path.rstrip('...')
288 local_path.rstrip('...')
ashariff6ffe502013-02-15 22:23:12 +0000289 full_local_path = os.path.join(root_dir, local_path)
290 ret = self._RsyncExcludingRepoDirs(remote_path, full_local_path)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800291 if ret:
292 return ret
asharif56d78bc2013-02-15 21:15:08 +0000293 return 0
asharifec9c6242013-02-15 19:56:06 +0000294
295
asharif0ea89582013-02-15 21:15:11 +0000296class RepoReader(object):
Caroline Tice88272d42016-01-13 09:48:29 -0800297 """Class for reading repositories."""
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800298
asharifec9c6242013-02-15 19:56:06 +0000299 def __init__(self, filename):
300 self.filename = filename
301 self.main_dict = {}
302 self.input_repos = []
303 self.output_repos = []
304
asharifec9c6242013-02-15 19:56:06 +0000305 def ParseFile(self):
asharif0ea89582013-02-15 21:15:11 +0000306 with open(self.filename) as f:
Caroline Tice88272d42016-01-13 09:48:29 -0800307 self.main_dict = json.load(f)
asharif0ea89582013-02-15 21:15:11 +0000308 self.CreateReposFromDict(self.main_dict)
asharifec9c6242013-02-15 19:56:06 +0000309 return [self.input_repos, self.output_repos]
310
asharifec9c6242013-02-15 19:56:06 +0000311 def CreateReposFromDict(self, main_dict):
asharif0ea89582013-02-15 21:15:11 +0000312 for key, repo_list in main_dict.items():
asharifec9c6242013-02-15 19:56:06 +0000313 for repo_dict in repo_list:
314 repo = self.CreateRepoFromDict(repo_dict)
asharif0ea89582013-02-15 21:15:11 +0000315 if key == 'input':
asharifec9c6242013-02-15 19:56:06 +0000316 self.input_repos.append(repo)
asharif0ea89582013-02-15 21:15:11 +0000317 elif key == 'output':
asharifec9c6242013-02-15 19:56:06 +0000318 self.output_repos.append(repo)
319 else:
asharif0ea89582013-02-15 21:15:11 +0000320 logger.GetLogger().LogFatal('Unknown key: %s found' % key)
asharifec9c6242013-02-15 19:56:06 +0000321
asharifec9c6242013-02-15 19:56:06 +0000322 def CreateRepoFromDict(self, repo_dict):
asharif0ea89582013-02-15 21:15:11 +0000323 repo_type = repo_dict.get('type', None)
324 repo_address = repo_dict.get('address', None)
325 repo_mappings = repo_dict.get('mappings', None)
326 repo_ignores = repo_dict.get('ignores', None)
327 repo_branch = repo_dict.get('branch', None)
asharif2aeeaca2013-02-16 02:11:04 +0000328 gerrit = repo_dict.get('gerrit', None)
asharif6578cf82013-02-16 02:41:46 +0000329 revision = repo_dict.get('revision', None)
asharifec9c6242013-02-15 19:56:06 +0000330
asharif0ea89582013-02-15 21:15:11 +0000331 if repo_type == 'p4':
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800332 repo = P4Repo(repo_address, repo_mappings, revision=revision)
asharif0ea89582013-02-15 21:15:11 +0000333 elif repo_type == 'svn':
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800334 repo = SvnRepo(repo_address, repo_mappings)
asharif0ea89582013-02-15 21:15:11 +0000335 elif repo_type == 'git':
Caroline Ticef6ef4392017-04-06 17:16:05 -0700336 repo = GitRepo(
337 repo_address,
338 repo_branch,
339 mappings=repo_mappings,
340 ignores=repo_ignores,
341 gerrit=gerrit)
Han Sheneb77c442013-03-18 13:53:52 -0700342 elif repo_type == 'file':
343 repo = FileRepo(repo_address)
asharifec9c6242013-02-15 19:56:06 +0000344 else:
asharif0ea89582013-02-15 21:15:11 +0000345 logger.GetLogger().LogFatal('Unknown repo type: %s' % repo_type)
asharifec9c6242013-02-15 19:56:06 +0000346 return repo
347
348
asharif1b92e732013-02-15 20:51:38 +0000349@logger.HandleUncaughtExceptions
asharifec9c6242013-02-15 19:56:06 +0000350def Main(argv):
Caroline Tice88272d42016-01-13 09:48:29 -0800351 parser = argparse.ArgumentParser()
Caroline Ticef6ef4392017-04-06 17:16:05 -0700352 parser.add_argument(
353 '-i',
354 '--input_file',
355 dest='input_file',
356 help='The input file that contains repo descriptions.')
asharifec9c6242013-02-15 19:56:06 +0000357
Caroline Ticef6ef4392017-04-06 17:16:05 -0700358 parser.add_argument(
359 '-n',
360 '--dry_run',
361 dest='dry_run',
362 action='store_true',
363 default=False,
364 help='Do a dry run of the push.')
asharifec9c6242013-02-15 19:56:06 +0000365
Caroline Ticef6ef4392017-04-06 17:16:05 -0700366 parser.add_argument(
367 '-F',
368 '--message_file',
369 dest='message_file',
370 default=None,
371 help=('Use contents of the log file as the commit '
372 'message.'))
asharif983c7c42013-02-16 02:13:01 +0000373
Caroline Tice88272d42016-01-13 09:48:29 -0800374 options = parser.parse_args(argv)
asharifec9c6242013-02-15 19:56:06 +0000375 if not options.input_file:
376 parser.print_help()
377 return 1
378 rr = RepoReader(options.input_file)
379 [input_repos, output_repos] = rr.ParseFile()
380
Han Sheneb77c442013-03-18 13:53:52 -0700381 # Make sure FileRepo is not used as output destination.
382 for output_repo in output_repos:
383 if output_repo.repo_type == 'file':
384 logger.GetLogger().LogFatal(
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800385 'FileRepo is only supported as an input repo.')
Han Sheneb77c442013-03-18 13:53:52 -0700386
asharifec9c6242013-02-15 19:56:06 +0000387 for output_repo in output_repos:
asharif56d78bc2013-02-15 21:15:08 +0000388 ret = output_repo.SetupForPush()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800389 if ret:
390 return ret
asharifec9c6242013-02-15 19:56:06 +0000391
392 input_revisions = []
393 for input_repo in input_repos:
asharif56d78bc2013-02-15 21:15:08 +0000394 ret = input_repo.PullSources()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800395 if ret:
396 return ret
asharifec9c6242013-02-15 19:56:06 +0000397 input_revisions.append(input_repo.revision)
398
asharif56d78bc2013-02-15 21:15:08 +0000399 for input_repo in input_repos:
400 for output_repo in output_repos:
401 ret = input_repo.MapSources(output_repo.GetRoot())
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800402 if ret:
403 return ret
asharif56d78bc2013-02-15 21:15:08 +0000404
asharif0ea89582013-02-15 21:15:11 +0000405 commit_message = 'Synced repos to: %s' % ','.join(input_revisions)
asharifec9c6242013-02-15 19:56:06 +0000406 for output_repo in output_repos:
Caroline Ticef6ef4392017-04-06 17:16:05 -0700407 ret = output_repo.PushSources(
408 commit_message=commit_message,
409 dry_run=options.dry_run,
410 message_file=options.message_file)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800411 if ret:
412 return ret
asharifcdbacaf2013-02-15 20:09:23 +0000413
414 if not options.dry_run:
asharif56d78bc2013-02-15 21:15:08 +0000415 for output_repo in output_repos:
416 output_repo.CleanupRoot()
raymes80780842013-02-15 21:59:10 +0000417 for input_repo in input_repos:
418 input_repo.CleanupRoot()
asharifcdbacaf2013-02-15 20:09:23 +0000419
420 return ret
asharifec9c6242013-02-15 19:56:06 +0000421
422
asharif0ea89582013-02-15 21:15:11 +0000423if __name__ == '__main__':
Caroline Tice88272d42016-01-13 09:48:29 -0800424 retval = Main(sys.argv[1:])
asharifec9c6242013-02-15 19:56:06 +0000425 sys.exit(retval)