gclient_test.py 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  1. #!/usr/bin/env vpython3
  2. # Copyright (c) 2012 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Unit tests for gclient.py.
  6. See gclient_smoketest.py for integration tests.
  7. """
  8. import json
  9. import logging
  10. import ntpath
  11. import os
  12. import queue
  13. import sys
  14. import unittest
  15. from unittest import mock
  16. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  17. import metrics_utils
  18. # We have to disable monitoring before importing gclient.
  19. metrics_utils.COLLECT_METRICS = False
  20. import gclient
  21. import gclient_eval
  22. import gclient_utils
  23. from testing_support import trial_dir
  24. # TODO: Should fix these warnings.
  25. # pylint: disable=line-too-long
  26. def write(filename, content):
  27. """Writes the content of a file and create the directories as needed."""
  28. filename = os.path.abspath(filename)
  29. dirname = os.path.dirname(filename)
  30. if not os.path.isdir(dirname):
  31. os.makedirs(dirname)
  32. with open(filename, 'w') as f:
  33. f.write(content)
  34. class CIPDRootMock(object):
  35. def __init__(self, root_dir, service_url):
  36. self.root_dir = root_dir
  37. self.service_url = service_url
  38. def expand_package_name(self, package_name):
  39. return package_name
  40. class SCMMock(object):
  41. unit_test = None
  42. def __init__(self,
  43. parsed_url,
  44. root_dir,
  45. name,
  46. out_fh=None,
  47. out_cb=None,
  48. print_outbuf=False):
  49. self.unit_test.assertTrue(parsed_url.startswith('svn://example.com/'),
  50. parsed_url)
  51. self.unit_test.assertTrue(root_dir.startswith(self.unit_test.root_dir),
  52. root_dir)
  53. self.name = name
  54. self.url = parsed_url
  55. def RunCommand(self, command, options, args, file_list):
  56. self.unit_test.assertEqual('None', command)
  57. self.unit_test.processed.put((self.name, self.url))
  58. # pylint: disable=no-self-use
  59. def DoesRemoteURLMatch(self, _):
  60. return True
  61. def GetActualRemoteURL(self, _):
  62. return self.url
  63. def revinfo(self, _, _a, _b):
  64. return 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
  65. class GclientTest(trial_dir.TestCase):
  66. def setUp(self):
  67. super(GclientTest, self).setUp()
  68. self.processed = queue.Queue()
  69. self.previous_dir = os.getcwd()
  70. os.chdir(self.root_dir)
  71. # Manual mocks.
  72. self._old_createscm = gclient.gclient_scm.GitWrapper
  73. gclient.gclient_scm.GitWrapper = SCMMock
  74. SCMMock.unit_test = self
  75. mock.patch('os.environ', {}).start()
  76. self.addCleanup(mock.patch.stopall)
  77. def tearDown(self):
  78. self.assertEqual([], self._get_processed())
  79. gclient.gclient_scm.GitWrapper = self._old_createscm
  80. os.chdir(self.previous_dir)
  81. super(GclientTest, self).tearDown()
  82. def testDependencies(self):
  83. self._dependencies('1')
  84. def testDependenciesJobs(self):
  85. self._dependencies('1000')
  86. def _dependencies(self, jobs):
  87. """Verifies that dependencies are processed in the right order.
  88. e.g. if there is a dependency 'src' and another 'src/third_party/bar', that
  89. bar isn't fetched until 'src' is done.
  90. Args:
  91. |jobs| is the number of parallel jobs simulated.
  92. """
  93. parser = gclient.OptionParser()
  94. options, args = parser.parse_args(['--jobs', jobs])
  95. write(
  96. '.gclient', 'solutions = [\n'
  97. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  98. ' { "name": "bar", "url": "svn://example.com/bar" },\n'
  99. ' { "name": "bar/empty", "url": "svn://example.com/bar_empty" },\n'
  100. ']')
  101. write(
  102. os.path.join('foo', 'DEPS'),
  103. 'deps = {\n'
  104. ' "foo/dir1": "/dir1",\n'
  105. # This one will depend on dir1/dir2 in bar.
  106. ' "foo/dir1/dir2/dir3": "/dir1/dir2/dir3",\n'
  107. ' "foo/dir1/dir2/dir3/dir4": "/dir1/dir2/dir3/dir4",\n'
  108. '}')
  109. write(
  110. os.path.join('bar', 'DEPS'),
  111. 'deps = {\n'
  112. # There is two foo/dir1/dir2. This one is fetched as bar/dir1/dir2.
  113. ' "foo/dir1/dir2": "/dir1/dir2",\n'
  114. '}')
  115. write(os.path.join('bar/empty', 'DEPS'), 'deps = {\n' '}')
  116. obj = gclient.GClient.LoadCurrentConfig(options)
  117. self._check_requirements(obj.dependencies[0], {})
  118. self._check_requirements(obj.dependencies[1], {})
  119. obj.RunOnDeps('None', args)
  120. actual = self._get_processed()
  121. first_3 = [
  122. ('bar', 'svn://example.com/bar'),
  123. ('bar/empty', 'svn://example.com/bar_empty'),
  124. ('foo', 'svn://example.com/foo'),
  125. ]
  126. if jobs != 1:
  127. # We don't care of the ordering of these items except that bar must
  128. # be before bar/empty.
  129. self.assertTrue(
  130. actual.index(('bar', 'svn://example.com/bar')) < actual.index((
  131. 'bar/empty', 'svn://example.com/bar_empty')))
  132. self.assertEqual(first_3, sorted(actual[0:3]))
  133. else:
  134. self.assertEqual(first_3, actual[0:3])
  135. self.assertEqual([
  136. ('foo/dir1', 'svn://example.com/dir1'),
  137. ('foo/dir1/dir2', 'svn://example.com/dir1/dir2'),
  138. ('foo/dir1/dir2/dir3', 'svn://example.com/dir1/dir2/dir3'),
  139. ('foo/dir1/dir2/dir3/dir4',
  140. 'svn://example.com/dir1/dir2/dir3/dir4'),
  141. ], actual[3:])
  142. self.assertEqual(3, len(obj.dependencies))
  143. self.assertEqual('foo', obj.dependencies[0].name)
  144. self.assertEqual('bar', obj.dependencies[1].name)
  145. self.assertEqual('bar/empty', obj.dependencies[2].name)
  146. self._check_requirements(
  147. obj.dependencies[0], {
  148. 'foo/dir1': ['bar', 'bar/empty', 'foo'],
  149. 'foo/dir1/dir2/dir3':
  150. ['bar', 'bar/empty', 'foo', 'foo/dir1', 'foo/dir1/dir2'],
  151. 'foo/dir1/dir2/dir3/dir4': [
  152. 'bar', 'bar/empty', 'foo', 'foo/dir1', 'foo/dir1/dir2',
  153. 'foo/dir1/dir2/dir3'
  154. ],
  155. })
  156. self._check_requirements(obj.dependencies[1], {
  157. 'foo/dir1/dir2': ['bar', 'bar/empty', 'foo', 'foo/dir1'],
  158. })
  159. self._check_requirements(obj.dependencies[2], {})
  160. self._check_requirements(obj, {
  161. 'foo': [],
  162. 'bar': [],
  163. 'bar/empty': ['bar'],
  164. })
  165. def _check_requirements(self, solution, expected):
  166. for dependency in solution.dependencies:
  167. e = expected.pop(dependency.name)
  168. a = sorted(dependency.requirements)
  169. self.assertEqual(e, a, (dependency.name, e, a))
  170. self.assertEqual({}, expected)
  171. def _get_processed(self):
  172. """Retrieves the item in the order they were processed."""
  173. items = []
  174. try:
  175. while True:
  176. items.append(self.processed.get_nowait())
  177. except queue.Empty:
  178. pass
  179. return items
  180. def _get_hooks(self):
  181. """Retrieves the hooks that would be run"""
  182. parser = gclient.OptionParser()
  183. options, _ = parser.parse_args([])
  184. options.force = True
  185. client = gclient.GClient.LoadCurrentConfig(options)
  186. work_queue = gclient_utils.ExecutionQueue(options.jobs, None, False)
  187. for s in client.dependencies:
  188. work_queue.enqueue(s)
  189. work_queue.flush({},
  190. None, [],
  191. options=options,
  192. patch_refs={},
  193. target_branches={},
  194. skip_sync_revisions={})
  195. return client.GetHooks(options)
  196. def testAutofix(self):
  197. # Invalid urls causes pain when specifying requirements. Make sure it's
  198. # auto-fixed.
  199. url = 'proto://host/path/@revision'
  200. d = gclient.Dependency(parent=None,
  201. name='name',
  202. url=url,
  203. managed=None,
  204. custom_deps=None,
  205. custom_vars=None,
  206. custom_hooks=None,
  207. deps_file='',
  208. should_process=True,
  209. should_recurse=False,
  210. relative=False,
  211. condition=None,
  212. protocol='https',
  213. print_outbuf=True)
  214. self.assertEqual('proto://host/path@revision', d.url)
  215. def testStr(self):
  216. parser = gclient.OptionParser()
  217. options, _ = parser.parse_args([])
  218. obj = gclient.GClient('foo', options)
  219. obj.add_dependencies_and_close([
  220. gclient.Dependency(parent=obj,
  221. name='foo',
  222. url='svn://example.com/foo',
  223. managed=None,
  224. custom_deps=None,
  225. custom_vars=None,
  226. custom_hooks=None,
  227. deps_file='DEPS',
  228. should_process=True,
  229. should_recurse=True,
  230. relative=False,
  231. condition=None,
  232. protocol='https',
  233. print_outbuf=True),
  234. gclient.Dependency(parent=obj,
  235. name='bar',
  236. url='svn://example.com/bar',
  237. managed=None,
  238. custom_deps=None,
  239. custom_vars=None,
  240. custom_hooks=None,
  241. deps_file='DEPS',
  242. should_process=True,
  243. should_recurse=False,
  244. relative=False,
  245. condition=None,
  246. protocol='https',
  247. print_outbuf=True),
  248. ], [])
  249. obj.dependencies[0].add_dependencies_and_close([
  250. gclient.Dependency(parent=obj.dependencies[0],
  251. name='foo/dir1',
  252. url='svn://example.com/foo/dir1',
  253. managed=None,
  254. custom_deps=None,
  255. custom_vars=None,
  256. custom_hooks=None,
  257. deps_file='DEPS',
  258. should_process=True,
  259. should_recurse=False,
  260. relative=False,
  261. condition=None,
  262. protocol='https',
  263. print_outbuf=True),
  264. ], [])
  265. # TODO(ehmaldonado): Improve this test.
  266. # Make sure __str__() works fine.
  267. # pylint: disable=protected-access
  268. obj.dependencies[0]._file_list.append('foo')
  269. str_obj = str(obj)
  270. self.assertEqual(322, len(str_obj), '%d\n%s' % (len(str_obj), str_obj))
  271. def testHooks(self):
  272. hooks = [{'pattern': '.', 'action': ['cmd1', 'arg1', 'arg2']}]
  273. write(
  274. '.gclient', 'solutions = [{\n'
  275. ' "name": "top",\n'
  276. ' "url": "svn://example.com/top"\n'
  277. '}]')
  278. write(os.path.join('top', 'DEPS'), 'hooks = %s' % repr(hooks))
  279. write(os.path.join('top', 'fake.txt'), "bogus content")
  280. self.assertEqual([h.action for h in self._get_hooks()],
  281. [tuple(x['action']) for x in hooks])
  282. def testCustomHooks(self):
  283. extra_hooks = [{
  284. 'name': 'append',
  285. 'pattern': '.',
  286. 'action': ['supercmd']
  287. }]
  288. write(
  289. '.gclient', 'solutions = [\n'
  290. ' {\n'
  291. ' "name": "top",\n'
  292. ' "url": "svn://example.com/top",\n' +
  293. (' "custom_hooks": %s' % repr(extra_hooks + [{
  294. 'name': 'skip'
  295. }])) + ' },\n'
  296. ' {\n'
  297. ' "name": "bottom",\n'
  298. ' "url": "svn://example.com/bottom"\n'
  299. ' }\n'
  300. ']')
  301. hooks = [
  302. {
  303. 'pattern': '.',
  304. 'action': ['cmd1', 'arg1', 'arg2']
  305. },
  306. {
  307. 'pattern': '.',
  308. 'action': ['cmd2', 'arg1', 'arg2']
  309. },
  310. ]
  311. skip_hooks = [
  312. {
  313. 'name': 'skip',
  314. 'pattern': '.',
  315. 'action': ['cmd3', 'arg1', 'arg2']
  316. },
  317. {
  318. 'name': 'skip',
  319. 'pattern': '.',
  320. 'action': ['cmd4', 'arg1', 'arg2']
  321. },
  322. ]
  323. write(os.path.join('top', 'DEPS'),
  324. 'hooks = %s' % repr(hooks + skip_hooks))
  325. # Make sure the custom hooks for that project don't affect the next one.
  326. sub_hooks = [
  327. {
  328. 'pattern': '.',
  329. 'action': ['response1', 'yes1', 'yes2']
  330. },
  331. {
  332. 'name': 'skip',
  333. 'pattern': '.',
  334. 'action': ['response2', 'yes', 'sir']
  335. },
  336. ]
  337. write(os.path.join('bottom', 'DEPS'), 'hooks = %s' % repr(sub_hooks))
  338. write(os.path.join('bottom', 'fake.txt'), "bogus content")
  339. self.assertEqual(
  340. [h.action for h in self._get_hooks()],
  341. [tuple(x['action']) for x in hooks + extra_hooks + sub_hooks])
  342. def testRecurseDepsAndHooks(self):
  343. """Verifies that hooks in recursedeps are ran."""
  344. write(
  345. '.gclient', 'solutions = [\n'
  346. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  347. ']')
  348. write(
  349. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  350. 'deps = {\n'
  351. ' "bar": "/bar",\n'
  352. '}\n'
  353. 'recursedeps = ["bar"]')
  354. write(
  355. os.path.join('foo', 'bar', 'DEPS'), 'hooks = [{\n'
  356. ' "name": "toto",\n'
  357. ' "pattern": ".",\n'
  358. ' "action": ["tata", "titi"]\n'
  359. '}]\n')
  360. write(os.path.join('foo', 'bar', 'fake.txt'), "bogus content")
  361. self.assertEqual([h.action for h in self._get_hooks()],
  362. [('tata', 'titi')])
  363. def testRecurseDepsAndHooksCwd(self):
  364. """Verifies that hooks run in the correct directory with our without
  365. use_relative_paths"""
  366. write(
  367. '.gclient', 'solutions = [\n'
  368. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  369. ']')
  370. write(
  371. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  372. 'deps = {\n'
  373. ' "bar": "/bar",\n'
  374. ' "baz": "/baz",\n'
  375. '}\n'
  376. 'recursedeps = ["bar", "baz"]')
  377. write(
  378. os.path.join('foo', 'bar', 'DEPS'), 'hooks = [{\n'
  379. ' "name": "toto",\n'
  380. ' "pattern": ".",\n'
  381. ' "action": ["tata", "titi"]\n'
  382. '}]\n')
  383. write(os.path.join('foo', 'bar', 'fake.txt'), "bogus content")
  384. write(
  385. os.path.join('foo', 'baz', 'DEPS'), 'use_relative_paths=True\n'
  386. 'hooks = [{\n'
  387. ' "name": "lazors",\n'
  388. ' "pattern": ".",\n'
  389. ' "action": ["fire", "lazors"]\n'
  390. '}]\n')
  391. write(os.path.join('foo', 'baz', 'fake.txt'), "bogus content")
  392. self.assertEqual(
  393. [(h.action, h.effective_cwd) for h in self._get_hooks()],
  394. [(('tata', 'titi'), os.path.join(self.root_dir, 'foo')),
  395. (('fire', 'lazors'), os.path.join(self.root_dir, 'foo/baz'))])
  396. def testTargetOS(self):
  397. """Verifies that specifying a target_os pulls in all relevant dependencies.
  398. The target_os variable allows specifying the name of an additional OS which
  399. should be considered when selecting dependencies from a DEPS' deps_os. The
  400. value will be appended to the _enforced_os tuple.
  401. """
  402. write(
  403. '.gclient', 'solutions = [\n'
  404. ' { "name": "foo",\n'
  405. ' "url": "svn://example.com/foo",\n'
  406. ' }]\n'
  407. 'target_os = ["baz"]')
  408. write(
  409. os.path.join('foo', 'DEPS'), 'deps = {\n'
  410. ' "foo/dir1": "/dir1",'
  411. '}\n'
  412. 'deps_os = {\n'
  413. ' "unix": { "foo/dir2": "/dir2", },\n'
  414. ' "baz": { "foo/dir3": "/dir3", },\n'
  415. '}')
  416. parser = gclient.OptionParser()
  417. options, _ = parser.parse_args(['--jobs', '1'])
  418. options.deps_os = "unix"
  419. obj = gclient.GClient.LoadCurrentConfig(options)
  420. self.assertEqual(['baz', 'unix'], sorted(obj.enforced_os))
  421. def testTargetOsWithTargetOsOnly(self):
  422. """Verifies that specifying a target_os and target_os_only pulls in only
  423. the relevant dependencies.
  424. The target_os variable allows specifying the name of an additional OS which
  425. should be considered when selecting dependencies from a DEPS' deps_os. With
  426. target_os_only also set, the _enforced_os tuple will be set to only the
  427. target_os value.
  428. """
  429. write(
  430. '.gclient', 'solutions = [\n'
  431. ' { "name": "foo",\n'
  432. ' "url": "svn://example.com/foo",\n'
  433. ' }]\n'
  434. 'target_os = ["baz"]\n'
  435. 'target_os_only = True')
  436. write(
  437. os.path.join('foo', 'DEPS'), 'deps = {\n'
  438. ' "foo/dir1": "/dir1",'
  439. '}\n'
  440. 'deps_os = {\n'
  441. ' "unix": { "foo/dir2": "/dir2", },\n'
  442. ' "baz": { "foo/dir3": "/dir3", },\n'
  443. '}')
  444. parser = gclient.OptionParser()
  445. options, _ = parser.parse_args(['--jobs', '1'])
  446. options.deps_os = "unix"
  447. obj = gclient.GClient.LoadCurrentConfig(options)
  448. self.assertEqual(['baz'], sorted(obj.enforced_os))
  449. def testTargetOsOnlyWithoutTargetOs(self):
  450. """Verifies that specifying a target_os_only without target_os_only raises
  451. an exception.
  452. """
  453. write(
  454. '.gclient', 'solutions = [\n'
  455. ' { "name": "foo",\n'
  456. ' "url": "svn://example.com/foo",\n'
  457. ' }]\n'
  458. 'target_os_only = True')
  459. write(
  460. os.path.join('foo', 'DEPS'), 'deps = {\n'
  461. ' "foo/dir1": "/dir1",'
  462. '}\n'
  463. 'deps_os = {\n'
  464. ' "unix": { "foo/dir2": "/dir2", },\n'
  465. '}')
  466. parser = gclient.OptionParser()
  467. options, _ = parser.parse_args(['--jobs', '1'])
  468. options.deps_os = "unix"
  469. exception_raised = False
  470. try:
  471. gclient.GClient.LoadCurrentConfig(options)
  472. except gclient_utils.Error:
  473. exception_raised = True
  474. self.assertTrue(exception_raised)
  475. def testTargetOsInDepsFile(self):
  476. """Verifies that specifying a target_os value in a DEPS file pulls in all
  477. relevant dependencies.
  478. The target_os variable in a DEPS file allows specifying the name of an
  479. additional OS which should be considered when selecting dependencies from a
  480. DEPS' deps_os. The value will be appended to the _enforced_os tuple.
  481. """
  482. write(
  483. '.gclient', 'solutions = [\n'
  484. ' { "name": "foo",\n'
  485. ' "url": "svn://example.com/foo",\n'
  486. ' },\n'
  487. ' { "name": "bar",\n'
  488. ' "url": "svn://example.com/bar",\n'
  489. ' }]\n')
  490. write(os.path.join('foo', 'DEPS'), 'target_os = ["baz"]\n')
  491. write(os.path.join('bar', 'DEPS'), '')
  492. parser = gclient.OptionParser()
  493. options, _ = parser.parse_args(['--jobs', '1'])
  494. options.deps_os = 'unix'
  495. obj = gclient.GClient.LoadCurrentConfig(options)
  496. obj.RunOnDeps('None', [])
  497. self.assertEqual(['unix'], sorted(obj.enforced_os))
  498. self.assertEqual([['baz', 'unix'], ['unix']],
  499. [sorted(dep.target_os) for dep in obj.dependencies])
  500. self.assertEqual([('foo', 'svn://example.com/foo'),
  501. ('bar', 'svn://example.com/bar')],
  502. self._get_processed())
  503. def testTargetOsForHooksInDepsFile(self):
  504. """Verifies that specifying a target_os value in a DEPS file runs the right
  505. entries in hooks_os.
  506. """
  507. write(
  508. 'DEPS', 'hooks = [\n'
  509. ' {\n'
  510. ' "name": "a",\n'
  511. ' "pattern": ".",\n'
  512. ' "action": [ "python", "do_a" ],\n'
  513. ' },\n'
  514. ']\n'
  515. '\n'
  516. 'hooks_os = {\n'
  517. ' "blorp": ['
  518. ' {\n'
  519. ' "name": "b",\n'
  520. ' "pattern": ".",\n'
  521. ' "action": [ "python", "do_b" ],\n'
  522. ' },\n'
  523. ' ],\n'
  524. '}\n')
  525. write(
  526. '.gclient', 'solutions = [\n'
  527. ' { "name": ".",\n'
  528. ' "url": "svn://example.com/",\n'
  529. ' }]\n')
  530. # Test for an OS not in hooks_os.
  531. parser = gclient.OptionParser()
  532. options, args = parser.parse_args(['--jobs', '1'])
  533. options.deps_os = 'zippy'
  534. obj = gclient.GClient.LoadCurrentConfig(options)
  535. obj.RunOnDeps('None', args)
  536. self.assertEqual(['zippy'], sorted(obj.enforced_os))
  537. all_hooks = obj.GetHooks(options)
  538. self.assertEqual([
  539. ('.', 'svn://example.com/'),
  540. ], sorted(self._get_processed()))
  541. self.assertEqual([h.action for h in all_hooks], [('python', 'do_a'),
  542. ('python', 'do_b')])
  543. self.assertEqual([h.condition for h in all_hooks],
  544. [None, 'checkout_blorp'])
  545. def testOverride(self):
  546. """Verifies expected behavior of URL overrides."""
  547. write(
  548. '.gclient', 'solutions = [\n'
  549. ' { "name": "foo",\n'
  550. ' "url": "svn://example.com/foo",\n'
  551. ' "custom_deps": {\n'
  552. ' "foo/bar": "svn://example.com/override",\n'
  553. ' "foo/skip2": None,\n'
  554. ' "foo/new": "svn://example.com/new",\n'
  555. ' },\n'
  556. ' },]\n')
  557. write(
  558. os.path.join('foo', 'DEPS'), 'vars = {\n'
  559. ' "origin": "svn://example.com",\n'
  560. '}\n'
  561. 'deps = {\n'
  562. ' "foo/skip": None,\n'
  563. ' "foo/bar": "{origin}/bar",\n'
  564. ' "foo/baz": "{origin}/baz",\n'
  565. ' "foo/skip2": "{origin}/skip2",\n'
  566. ' "foo/rel": "/rel",\n'
  567. '}')
  568. parser = gclient.OptionParser()
  569. options, _ = parser.parse_args(['--jobs', '1'])
  570. obj = gclient.GClient.LoadCurrentConfig(options)
  571. obj.RunOnDeps('None', [])
  572. sol = obj.dependencies[0]
  573. self.assertEqual([
  574. ('foo', 'svn://example.com/foo'),
  575. ('foo/bar', 'svn://example.com/override'),
  576. ('foo/baz', 'svn://example.com/baz'),
  577. ('foo/new', 'svn://example.com/new'),
  578. ('foo/rel', 'svn://example.com/rel'),
  579. ], self._get_processed())
  580. self.assertEqual(6, len(sol.dependencies))
  581. self.assertEqual([
  582. ('foo/bar', 'svn://example.com/override'),
  583. ('foo/baz', 'svn://example.com/baz'),
  584. ('foo/new', 'svn://example.com/new'),
  585. ('foo/rel', 'svn://example.com/rel'),
  586. ('foo/skip', None),
  587. ('foo/skip2', None),
  588. ], [(dep.name, dep.url) for dep in sol.dependencies])
  589. def testVarOverrides(self):
  590. """Verifies expected behavior of variable overrides."""
  591. write(
  592. '.gclient', 'solutions = [\n'
  593. ' { "name": "foo",\n'
  594. ' "url": "svn://example.com/foo",\n'
  595. ' "custom_vars": {\n'
  596. ' "path": "c-d",\n'
  597. ' },\n'
  598. ' },]\n')
  599. write(
  600. os.path.join('foo', 'DEPS'), 'vars = {\n'
  601. ' "path": Str("a-b"),\n'
  602. '}\n'
  603. 'deps = {\n'
  604. ' "foo/bar": "svn://example.com/foo/" + Var("path"),\n'
  605. '}')
  606. parser = gclient.OptionParser()
  607. options, _ = parser.parse_args(['--jobs', '1'])
  608. obj = gclient.GClient.LoadCurrentConfig(options)
  609. obj.RunOnDeps('None', [])
  610. sol = obj.dependencies[0]
  611. self.assertEqual([
  612. ('foo', 'svn://example.com/foo'),
  613. ('foo/bar', 'svn://example.com/foo/c-d'),
  614. ], self._get_processed())
  615. self.assertEqual(1, len(sol.dependencies))
  616. self.assertEqual([
  617. ('foo/bar', 'svn://example.com/foo/c-d'),
  618. ], [(dep.name, dep.url) for dep in sol.dependencies])
  619. def testDepsOsOverrideDepsInDepsFile(self):
  620. """Verifies that a 'deps_os' path cannot override a 'deps' path. Also
  621. see testUpdateWithOsDeps above.
  622. """
  623. write(
  624. '.gclient', 'solutions = [\n'
  625. ' { "name": "foo",\n'
  626. ' "url": "svn://example.com/foo",\n'
  627. ' },]\n')
  628. write(
  629. os.path.join('foo', 'DEPS'),
  630. 'target_os = ["baz"]\n'
  631. 'deps = {\n'
  632. ' "foo/src": "/src",\n' # This path is to be overridden by similar path
  633. # in deps_os['unix'].
  634. '}\n'
  635. 'deps_os = {\n'
  636. ' "unix": { "foo/unix": "/unix",'
  637. ' "foo/src": "/src_unix"},\n'
  638. ' "baz": { "foo/baz": "/baz",\n'
  639. ' "foo/src": None},\n'
  640. ' "jaz": { "foo/jaz": "/jaz", },\n'
  641. '}')
  642. parser = gclient.OptionParser()
  643. options, _ = parser.parse_args(['--jobs', '1'])
  644. options.deps_os = 'unix'
  645. obj = gclient.GClient.LoadCurrentConfig(options)
  646. with self.assertRaises(gclient_utils.Error):
  647. obj.RunOnDeps('None', [])
  648. self.assertEqual(['unix'], sorted(obj.enforced_os))
  649. self.assertEqual([
  650. ('foo', 'svn://example.com/foo'),
  651. ], sorted(self._get_processed()))
  652. def testRecursedepsOverride(self):
  653. """Verifies gclient respects the |recursedeps| var syntax.
  654. This is what we mean to check here:
  655. - |recursedeps| = [...] on 2 levels means we pull exactly 3 deps
  656. (up to /fizz, but not /fuzz)
  657. - pulling foo/bar with no recursion (in .gclient) is overridden by
  658. a later pull of foo/bar with recursion (in the dep tree)
  659. - pulling foo/tar with no recursion (in .gclient) is no recursively
  660. pulled (taz is left out)
  661. """
  662. write(
  663. '.gclient', 'solutions = [\n'
  664. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  665. ' { "name": "foo/bar", "url": "svn://example.com/bar" },\n'
  666. ' { "name": "foo/tar", "url": "svn://example.com/tar" },\n'
  667. ']')
  668. write(os.path.join('foo', 'DEPS'), 'deps = {\n'
  669. ' "bar": "/bar",\n'
  670. '}\n'
  671. 'recursedeps = ["bar"]')
  672. write(os.path.join('bar', 'DEPS'), 'deps = {\n'
  673. ' "baz": "/baz",\n'
  674. '}\n'
  675. 'recursedeps = ["baz"]')
  676. write(os.path.join('baz', 'DEPS'), 'deps = {\n'
  677. ' "fizz": "/fizz",\n'
  678. '}')
  679. write(os.path.join('fizz', 'DEPS'), 'deps = {\n'
  680. ' "fuzz": "/fuzz",\n'
  681. '}')
  682. write(os.path.join('tar', 'DEPS'), 'deps = {\n'
  683. ' "taz": "/taz",\n'
  684. '}')
  685. options, _ = gclient.OptionParser().parse_args([])
  686. obj = gclient.GClient.LoadCurrentConfig(options)
  687. obj.RunOnDeps('None', [])
  688. self.assertEqual([
  689. ('bar', 'svn://example.com/bar'),
  690. ('baz', 'svn://example.com/baz'),
  691. ('fizz', 'svn://example.com/fizz'),
  692. ('foo', 'svn://example.com/foo'),
  693. ('foo/bar', 'svn://example.com/bar'),
  694. ('foo/tar', 'svn://example.com/tar'),
  695. ], sorted(self._get_processed()))
  696. def testRecursedepsOverrideWithRelativePaths(self):
  697. """Verifies gclient respects |recursedeps| with relative paths."""
  698. write(
  699. '.gclient', 'solutions = [\n'
  700. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  701. ']')
  702. write(
  703. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  704. 'deps = {\n'
  705. ' "bar": "/bar",\n'
  706. '}\n'
  707. 'recursedeps = ["bar"]')
  708. write(os.path.join('foo/bar', 'DEPS'), 'deps = {\n'
  709. ' "baz": "/baz",\n'
  710. '}')
  711. write(os.path.join('baz', 'DEPS'), 'deps = {\n'
  712. ' "fizz": "/fizz",\n'
  713. '}')
  714. options, _ = gclient.OptionParser().parse_args([])
  715. obj = gclient.GClient.LoadCurrentConfig(options)
  716. obj.RunOnDeps('None', [])
  717. self.assertEqual([
  718. ('foo', 'svn://example.com/foo'),
  719. ('foo/bar', 'svn://example.com/bar'),
  720. ('foo/baz', 'svn://example.com/baz'),
  721. ], self._get_processed())
  722. def testRecursedepsCustomdepsOverride(self):
  723. """Verifies gclient overrides deps within recursedeps using custom deps"""
  724. write(
  725. '.gclient', 'solutions = [\n'
  726. ' { "name": "foo",\n'
  727. ' "url": "svn://example.com/foo",\n'
  728. ' "custom_deps": {\n'
  729. ' "foo/bar": "svn://example.com/override",\n'
  730. ' },\n'
  731. ' },]\n')
  732. write(
  733. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  734. 'deps = {\n'
  735. ' "bar": "/bar",\n'
  736. '}\n'
  737. 'recursedeps = ["bar"]')
  738. write(os.path.join('foo', 'bar', 'DEPS'), 'deps = {\n'
  739. ' "baz": "/baz",\n'
  740. '}')
  741. options, _ = gclient.OptionParser().parse_args([])
  742. obj = gclient.GClient.LoadCurrentConfig(options)
  743. obj.RunOnDeps('None', [])
  744. self.assertCountEqual([
  745. ('foo', 'svn://example.com/foo'),
  746. ('foo/bar', 'svn://example.com/override'),
  747. ('foo/foo/bar', 'svn://example.com/override'),
  748. ('foo/baz', 'svn://example.com/baz'),
  749. ], self._get_processed())
  750. def testRelativeRecursion(self):
  751. """Verifies that nested use_relative_paths is always respected."""
  752. write(
  753. '.gclient', 'solutions = [\n'
  754. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  755. ']')
  756. write(
  757. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  758. 'deps = {\n'
  759. ' "bar": "/bar",\n'
  760. '}\n'
  761. 'recursedeps = ["bar"]')
  762. write(
  763. os.path.join('foo/bar', 'DEPS'), 'use_relative_paths = True\n'
  764. 'deps = {\n'
  765. ' "baz": "/baz",\n'
  766. '}')
  767. write(os.path.join('baz', 'DEPS'), 'deps = {\n'
  768. ' "fizz": "/fizz",\n'
  769. '}')
  770. options, _ = gclient.OptionParser().parse_args([])
  771. obj = gclient.GClient.LoadCurrentConfig(options)
  772. obj.RunOnDeps('None', [])
  773. self.assertEqual([
  774. ('foo', 'svn://example.com/foo'),
  775. ('foo/bar', 'svn://example.com/bar'),
  776. ('foo/bar/baz', 'svn://example.com/baz'),
  777. ], self._get_processed())
  778. def testRelativeRecursionInNestedDir(self):
  779. """Verifies a gotcha of relative recursion where the parent uses relative
  780. paths but not the dependency being recursed in. In that case the recursed
  781. dependencies will only take into account the first directory of its path.
  782. In this test it can be seen in baz being placed in foo/third_party."""
  783. write(
  784. '.gclient', 'solutions = [\n'
  785. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  786. ']')
  787. write(
  788. os.path.join('foo', 'DEPS'), 'use_relative_paths = True\n'
  789. 'deps = {\n'
  790. ' "third_party/bar": "/bar",\n'
  791. '}\n'
  792. 'recursedeps = ["third_party/bar"]')
  793. write(os.path.join('foo/third_party/bar', 'DEPS'), 'deps = {\n'
  794. ' "baz": "/baz",\n'
  795. '}')
  796. write(os.path.join('baz', 'DEPS'), 'deps = {\n'
  797. ' "fizz": "/fizz",\n'
  798. '}')
  799. options, _ = gclient.OptionParser().parse_args([])
  800. obj = gclient.GClient.LoadCurrentConfig(options)
  801. obj.RunOnDeps('None', [])
  802. self.assertEqual([
  803. ('foo', 'svn://example.com/foo'),
  804. ('foo/third_party/bar', 'svn://example.com/bar'),
  805. ('foo/third_party/baz', 'svn://example.com/baz'),
  806. ], self._get_processed())
  807. def testRecursedepsAltfile(self):
  808. """Verifies gclient respects the |recursedeps| var syntax with overridden
  809. target DEPS file.
  810. This is what we mean to check here:
  811. - Naming an alternate DEPS file in recursedeps pulls from that one.
  812. """
  813. write(
  814. '.gclient', 'solutions = [\n'
  815. ' { "name": "foo", "url": "svn://example.com/foo" },\n'
  816. ']')
  817. write(
  818. os.path.join('foo', 'DEPS'), 'deps = {\n'
  819. ' "bar": "/bar",\n'
  820. '}\n'
  821. 'recursedeps = [("bar", "DEPS.alt")]')
  822. write(os.path.join('bar', 'DEPS'), 'ERROR ERROR ERROR')
  823. write(os.path.join('bar', 'DEPS.alt'), 'deps = {\n'
  824. ' "baz": "/baz",\n'
  825. '}')
  826. options, _ = gclient.OptionParser().parse_args([])
  827. obj = gclient.GClient.LoadCurrentConfig(options)
  828. obj.RunOnDeps('None', [])
  829. self.assertEqual([
  830. ('foo', 'svn://example.com/foo'),
  831. ('bar', 'svn://example.com/bar'),
  832. ('baz', 'svn://example.com/baz'),
  833. ], self._get_processed())
  834. def testGitDeps(self):
  835. """Verifies gclient respects a .DEPS.git deps file.
  836. Along the way, we also test that if both DEPS and .DEPS.git are present,
  837. that gclient does not read the DEPS file. This will reliably catch bugs
  838. where gclient is always hitting the wrong file (DEPS).
  839. """
  840. write(
  841. '.gclient', 'solutions = [\n'
  842. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  843. ' "deps_file" : ".DEPS.git",\n'
  844. ' },\n'
  845. ']')
  846. write(os.path.join('foo', '.DEPS.git'), 'deps = {\n'
  847. ' "bar": "/bar",\n'
  848. '}')
  849. write(os.path.join('foo', 'DEPS'), 'deps = {\n'
  850. ' "baz": "/baz",\n'
  851. '}')
  852. options, _ = gclient.OptionParser().parse_args([])
  853. obj = gclient.GClient.LoadCurrentConfig(options)
  854. obj.RunOnDeps('None', [])
  855. self.assertEqual([
  856. ('foo', 'svn://example.com/foo'),
  857. ('bar', 'svn://example.com/bar'),
  858. ], self._get_processed())
  859. def testGitDepsFallback(self):
  860. """Verifies gclient respects fallback to DEPS upon missing deps file."""
  861. write(
  862. '.gclient', 'solutions = [\n'
  863. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  864. ' "deps_file" : ".DEPS.git",\n'
  865. ' },\n'
  866. ']')
  867. write(os.path.join('foo', 'DEPS'), 'deps = {\n'
  868. ' "bar": "/bar",\n'
  869. '}')
  870. options, _ = gclient.OptionParser().parse_args([])
  871. obj = gclient.GClient.LoadCurrentConfig(options)
  872. obj.RunOnDeps('None', [])
  873. self.assertEqual([
  874. ('foo', 'svn://example.com/foo'),
  875. ('bar', 'svn://example.com/bar'),
  876. ], self._get_processed())
  877. def testIgnoresGitDependenciesWhenFlagIsSet(self):
  878. """Verifies that git deps are ignored if --ignore-dep-type git is set."""
  879. write(
  880. '.gclient', 'solutions = [\n'
  881. ' { "name": "foo", "url": "https://example.com/foo",\n'
  882. ' "deps_file" : ".DEPS.git",\n'
  883. ' },\n'
  884. ']')
  885. write(
  886. os.path.join('foo', 'DEPS'), 'vars = {\n'
  887. ' "lemur_version": "version:1234",\n'
  888. '}\n'
  889. 'deps = {\n'
  890. ' "bar": "/bar",\n'
  891. ' "baz": {\n'
  892. ' "packages": [{\n'
  893. ' "package": "lemur",\n'
  894. ' "version": Var("lemur_version"),\n'
  895. ' }],\n'
  896. ' "dep_type": "cipd",\n'
  897. ' }\n'
  898. '}')
  899. options, _ = gclient.OptionParser().parse_args([])
  900. options.ignore_dep_type = 'git'
  901. obj = gclient.GClient.LoadCurrentConfig(options)
  902. obj._cipd_root = CIPDRootMock('src', 'https://example.com')
  903. self.assertEqual(1, len(obj.dependencies))
  904. sol = obj.dependencies[0]
  905. sol._condition = 'some_condition'
  906. sol.ParseDepsFile()
  907. self.assertEqual(1, len(sol.dependencies))
  908. dep = sol.dependencies[0]
  909. self.assertIsInstance(dep, gclient.CipdDependency)
  910. self.assertEqual('https://example.com/lemur@version:1234', dep.url)
  911. def testDepsFromNotAllowedHostsUnspecified(self):
  912. """Verifies gclient works fine with DEPS without allowed_hosts."""
  913. write(
  914. '.gclient', 'solutions = [\n'
  915. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  916. ' "deps_file" : ".DEPS.git",\n'
  917. ' },\n'
  918. ']')
  919. write(os.path.join('foo', 'DEPS'), 'deps = {\n'
  920. ' "bar": "/bar",\n'
  921. '}')
  922. options, _ = gclient.OptionParser().parse_args([])
  923. obj = gclient.GClient.LoadCurrentConfig(options)
  924. obj.RunOnDeps('None', [])
  925. dep = obj.dependencies[0]
  926. self.assertEqual([], dep.findDepsFromNotAllowedHosts())
  927. self.assertEqual(frozenset(), dep.allowed_hosts)
  928. self._get_processed()
  929. def testDepsFromNotAllowedHostsOK(self):
  930. """Verifies gclient works fine with DEPS with proper allowed_hosts."""
  931. write(
  932. '.gclient', 'solutions = [\n'
  933. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  934. ' "deps_file" : ".DEPS.git",\n'
  935. ' },\n'
  936. ']')
  937. write(
  938. os.path.join('foo', '.DEPS.git'),
  939. 'allowed_hosts = ["example.com"]\n'
  940. 'deps = {\n'
  941. ' "bar": "svn://example.com/bar",\n'
  942. '}')
  943. options, _ = gclient.OptionParser().parse_args([])
  944. obj = gclient.GClient.LoadCurrentConfig(options)
  945. obj.RunOnDeps('None', [])
  946. dep = obj.dependencies[0]
  947. self.assertEqual([], dep.findDepsFromNotAllowedHosts())
  948. self.assertEqual(frozenset(['example.com']), dep.allowed_hosts)
  949. self._get_processed()
  950. def testDepsFromNotAllowedHostsBad(self):
  951. """Verifies gclient works fine with DEPS with proper allowed_hosts."""
  952. write(
  953. '.gclient', 'solutions = [\n'
  954. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  955. ' "deps_file" : ".DEPS.git",\n'
  956. ' },\n'
  957. ']')
  958. write(
  959. os.path.join('foo', '.DEPS.git'), 'allowed_hosts = ["other.com"]\n'
  960. 'deps = {\n'
  961. ' "bar": "svn://example.com/bar",\n'
  962. '}')
  963. options, _ = gclient.OptionParser().parse_args([])
  964. obj = gclient.GClient.LoadCurrentConfig(options)
  965. obj.RunOnDeps('None', [])
  966. dep = obj.dependencies[0]
  967. self.assertEqual(frozenset(['other.com']), dep.allowed_hosts)
  968. self.assertEqual([dep.dependencies[0]],
  969. dep.findDepsFromNotAllowedHosts())
  970. self._get_processed()
  971. def testDepsParseFailureWithEmptyAllowedHosts(self):
  972. """Verifies gclient fails with defined but empty allowed_hosts."""
  973. write(
  974. '.gclient', 'solutions = [\n'
  975. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  976. ' "deps_file" : ".DEPS.git",\n'
  977. ' },\n'
  978. ']')
  979. write(os.path.join('foo', 'DEPS'), 'allowed_hosts = []\n'
  980. 'deps = {\n'
  981. ' "bar": "/bar",\n'
  982. '}')
  983. options, _ = gclient.OptionParser().parse_args([])
  984. obj = gclient.GClient.LoadCurrentConfig(options)
  985. try:
  986. obj.RunOnDeps('None', [])
  987. self.fail()
  988. except gclient_utils.Error as e:
  989. self.assertIn('allowed_hosts must be', str(e))
  990. finally:
  991. self._get_processed()
  992. def testDepsParseFailureWithNonIterableAllowedHosts(self):
  993. """Verifies gclient fails with defined but non-iterable allowed_hosts."""
  994. write(
  995. '.gclient', 'solutions = [\n'
  996. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  997. ' "deps_file" : ".DEPS.git",\n'
  998. ' },\n'
  999. ']')
  1000. write(os.path.join('foo', 'DEPS'), 'allowed_hosts = None\n'
  1001. 'deps = {\n'
  1002. ' "bar": "/bar",\n'
  1003. '}')
  1004. options, _ = gclient.OptionParser().parse_args([])
  1005. obj = gclient.GClient.LoadCurrentConfig(options)
  1006. try:
  1007. obj.RunOnDeps('None', [])
  1008. self.fail()
  1009. except gclient_utils.Error as e:
  1010. self.assertIn('Key \'allowed_hosts\' error:', str(e))
  1011. finally:
  1012. self._get_processed()
  1013. def testCreatesCipdDependencies(self):
  1014. """Verifies that CIPD deps are created correctly."""
  1015. write(
  1016. '.gclient', 'solutions = [\n'
  1017. ' { "name": "foo", "url": "svn://example.com/foo",\n'
  1018. ' "deps_file" : ".DEPS.git",\n'
  1019. ' },\n'
  1020. ']')
  1021. write(
  1022. os.path.join('foo', 'DEPS'), 'vars = {\n'
  1023. ' "lemur_version": "version:1234",\n'
  1024. '}\n'
  1025. 'deps = {\n'
  1026. ' "bar": {\n'
  1027. ' "packages": [{\n'
  1028. ' "package": "lemur",\n'
  1029. ' "version": Var("lemur_version"),\n'
  1030. ' }],\n'
  1031. ' "dep_type": "cipd",\n'
  1032. ' }\n'
  1033. '}')
  1034. options, _ = gclient.OptionParser().parse_args([])
  1035. obj = gclient.GClient.LoadCurrentConfig(options)
  1036. obj._cipd_root = CIPDRootMock('src', 'https://example.com')
  1037. self.assertEqual(1, len(obj.dependencies))
  1038. sol = obj.dependencies[0]
  1039. sol._condition = 'some_condition'
  1040. sol.ParseDepsFile()
  1041. self.assertEqual(1, len(sol.dependencies))
  1042. dep = sol.dependencies[0]
  1043. self.assertIsInstance(dep, gclient.CipdDependency)
  1044. self.assertEqual('https://example.com/lemur@version:1234', dep.url)
  1045. def testIgnoresCipdDependenciesWhenFlagIsSet(self):
  1046. """Verifies that CIPD deps are ignored if --ignore-dep-type cipd is set."""
  1047. write(
  1048. '.gclient', 'solutions = [\n'
  1049. ' { "name": "foo", "url": "https://example.com/foo",\n'
  1050. ' "deps_file" : ".DEPS.git",\n'
  1051. ' },\n'
  1052. ']')
  1053. write(
  1054. os.path.join('foo', 'DEPS'), 'vars = {\n'
  1055. ' "lemur_version": "version:1234",\n'
  1056. '}\n'
  1057. 'deps = {\n'
  1058. ' "bar": "/bar",\n'
  1059. ' "baz": {\n'
  1060. ' "packages": [{\n'
  1061. ' "package": "lemur",\n'
  1062. ' "version": Var("lemur_version"),\n'
  1063. ' }],\n'
  1064. ' "dep_type": "cipd",\n'
  1065. ' }\n'
  1066. '}')
  1067. options, _ = gclient.OptionParser().parse_args([])
  1068. options.ignore_dep_type = 'cipd'
  1069. obj = gclient.GClient.LoadCurrentConfig(options)
  1070. self.assertEqual(1, len(obj.dependencies))
  1071. sol = obj.dependencies[0]
  1072. sol._condition = 'some_condition'
  1073. sol.ParseDepsFile()
  1074. self.assertEqual(1, len(sol.dependencies))
  1075. dep = sol.dependencies[0]
  1076. self.assertIsInstance(dep, gclient.GitDependency)
  1077. self.assertEqual('https://example.com/bar', dep.url)
  1078. def testParseDepsFile_FalseShouldSync_WithCustoms(self):
  1079. """Only process custom_deps/hooks when should_sync is False."""
  1080. solutions = [{
  1081. 'name':
  1082. 'chicken',
  1083. 'url':
  1084. 'https://example.com/chicken',
  1085. 'deps_file':
  1086. '.DEPS.git',
  1087. 'custom_deps': {
  1088. 'override/foo': 'https://example.com/overridefoo@123',
  1089. 'new/foo': 'https://example.come/newfoo@123'
  1090. },
  1091. 'custom_hooks': [{
  1092. 'name': 'overridehook',
  1093. 'pattern': '.',
  1094. 'action': ['echo', 'chicken']
  1095. }, {
  1096. 'name': 'newhook',
  1097. 'pattern': '.',
  1098. 'action': ['echo', 'chick']
  1099. }],
  1100. }]
  1101. write('.gclient', 'solutions = %s' % repr(solutions))
  1102. deps = {
  1103. 'override/foo': 'https://example.com/override.git@bar_version',
  1104. 'notouch/foo': 'https://example.com/notouch.git@bar_version'
  1105. }
  1106. hooks = [{
  1107. 'name': 'overridehook',
  1108. 'pattern': '.',
  1109. 'action': ['echo', 'cow']
  1110. }, {
  1111. 'name': 'notouchhook',
  1112. 'pattern': '.',
  1113. 'action': ['echo', 'fail']
  1114. }]
  1115. pre_deps_hooks = [{
  1116. 'name': 'runfirst',
  1117. 'pattern': '.',
  1118. 'action': ['echo', 'prehook']
  1119. }]
  1120. write(
  1121. os.path.join('chicken', 'DEPS'), 'deps = %s\n'
  1122. 'hooks = %s\n'
  1123. 'pre_deps_hooks = %s' %
  1124. (repr(deps), repr(hooks), repr(pre_deps_hooks)))
  1125. expected_dep_names = ['override/foo', 'new/foo']
  1126. expected_hook_names = ['overridehook', 'newhook']
  1127. options, _ = gclient.OptionParser().parse_args([])
  1128. client = gclient.GClient.LoadCurrentConfig(options)
  1129. self.assertEqual(1, len(client.dependencies))
  1130. sol = client.dependencies[0]
  1131. sol._should_sync = False
  1132. sol.ParseDepsFile()
  1133. self.assertEqual(1, len(sol.pre_deps_hooks))
  1134. self.assertCountEqual(expected_dep_names,
  1135. [d.name for d in sol.dependencies])
  1136. self.assertCountEqual(expected_hook_names,
  1137. [h.name for h in sol._deps_hooks])
  1138. def testParseDepsFile_FalseShouldSync_NoCustoms(self):
  1139. """Parse DEPS when should_sync is False and no custom hooks/deps."""
  1140. solutions = [{
  1141. 'name': 'chicken',
  1142. 'url': 'https://example.com/chicken',
  1143. 'deps_file': '.DEPS.git',
  1144. }]
  1145. write('.gclient', 'solutions = %s' % repr(solutions))
  1146. deps = {
  1147. 'override/foo': 'https://example.com/override.git@bar_version',
  1148. 'notouch/foo': 'https://example.com/notouch.git@bar_version'
  1149. }
  1150. hooks = [{
  1151. 'name': 'overridehook',
  1152. 'pattern': '.',
  1153. 'action': ['echo', 'cow']
  1154. }, {
  1155. 'name': 'notouchhook',
  1156. 'pattern': '.',
  1157. 'action': ['echo', 'fail']
  1158. }]
  1159. pre_deps_hooks = [{
  1160. 'name': 'runfirst',
  1161. 'pattern': '.',
  1162. 'action': ['echo', 'prehook']
  1163. }]
  1164. write(
  1165. os.path.join('chicken', 'DEPS'), 'deps = %s\n'
  1166. 'hooks = %s\n'
  1167. 'pre_deps_hooks = %s' %
  1168. (repr(deps), repr(hooks), repr(pre_deps_hooks)))
  1169. options, _ = gclient.OptionParser().parse_args([])
  1170. client = gclient.GClient.LoadCurrentConfig(options)
  1171. self.assertEqual(1, len(client.dependencies))
  1172. sol = client.dependencies[0]
  1173. sol._should_sync = False
  1174. sol.ParseDepsFile()
  1175. self.assertFalse(sol.pre_deps_hooks)
  1176. self.assertFalse(sol.dependencies)
  1177. self.assertFalse(sol._deps_hooks)
  1178. def testParseGitSubmodules_NoSubmodules(self):
  1179. """ParseGitSubmodules should return {} when the dep doesn't have
  1180. submodules."""
  1181. solutions = [{
  1182. 'name': 'foobar',
  1183. 'url': 'https://example.com/foobar',
  1184. 'deps_file': '.DEPS.git',
  1185. }]
  1186. write('.gclient', 'solutions = %s' % repr(solutions))
  1187. options, _ = gclient.OptionParser().parse_args([])
  1188. client = gclient.GClient.LoadCurrentConfig(options)
  1189. self.assertEqual(1, len(client.dependencies))
  1190. sol = client.dependencies[0]
  1191. self.assertEqual(sol.ParseGitSubmodules(), {})
  1192. def testParseGitSubmodules_ParsesSubmodules(self):
  1193. """ParseGitSubmodules returns submodules when present."""
  1194. solutions = [{
  1195. 'name': 'foobar',
  1196. 'url': 'https://example.com/foobar',
  1197. 'deps_file': '.DEPS.git',
  1198. }]
  1199. write('.gclient', 'solutions = %s' % repr(solutions))
  1200. ls_files = """160000 be8c5114d606692dc783b60cf256690b62fbad17 0\tfoo/bar
  1201. 160000 3ad3b564f8ae456f286446d091709f5a09fa4a93 0\taaaaaa
  1202. 160000 956df937508b65b5e72a4cf02696255be3631b78 0\ta.a.a/a
  1203. 160000 b9f77763f0fab67eeeb6371492166567a8b7a3d2 0\ta_b/c
  1204. 160000 b9f77763f0fab67eeeb6371492166567a8b7a3d2 0\ta b/c"""
  1205. git_config = """submodule.foo/bar.path=foo/bar
  1206. submodule.foo/bar.url=http://example.com/foo/bar
  1207. submodule.foo/bar.gclient-condition=checkout_linux
  1208. submodule.aaaaaa.path=aaaaaa
  1209. submodule.aaaaaa.url=http://example.com/aaaaaa
  1210. submodule.a.a.a/a.path=a.a.a/a
  1211. submodule.a.a.a/a.url=http://example.com/a.a.a/a
  1212. submodule.a_b/c.path=a_b/c
  1213. submodule.a_b/c.url=http://example.com/a_b/c
  1214. submodule.a b/c.path=a b/c
  1215. submodule.a b/c.url=http://example.com/a%20b/c"""
  1216. os_path_isfile_mock = mock.MagicMock(return_value=True)
  1217. subprocess2_check_output_mock = mock.MagicMock(
  1218. side_effect=[git_config.encode(),
  1219. ls_files.encode()])
  1220. options, _ = gclient.OptionParser().parse_args([])
  1221. client = gclient.GClient.LoadCurrentConfig(options)
  1222. self.assertEqual(1, len(client.dependencies))
  1223. sol = client.dependencies[0]
  1224. sol._use_relative_paths = True
  1225. with mock.patch('os.path.isfile', os_path_isfile_mock), mock.patch(
  1226. 'subprocess2.check_output', subprocess2_check_output_mock):
  1227. self.assertEqual(
  1228. sol.ParseGitSubmodules(), {
  1229. 'foo/bar': {
  1230. 'dep_type':
  1231. 'git',
  1232. 'url': ('http://example.com/foo/bar@' +
  1233. 'be8c5114d606692dc783b60cf256690b62fbad17'),
  1234. 'condition':
  1235. 'checkout_linux',
  1236. },
  1237. 'aaaaaa': {
  1238. 'dep_type':
  1239. 'git',
  1240. 'url': ('http://example.com/aaaaaa@' +
  1241. '3ad3b564f8ae456f286446d091709f5a09fa4a93'),
  1242. },
  1243. 'a.a.a/a': {
  1244. 'dep_type':
  1245. 'git',
  1246. 'url': ('http://example.com/a.a.a/a@' +
  1247. '956df937508b65b5e72a4cf02696255be3631b78'),
  1248. },
  1249. 'a_b/c': {
  1250. 'dep_type':
  1251. 'git',
  1252. 'url': ('http://example.com/a_b/c@' +
  1253. 'b9f77763f0fab67eeeb6371492166567a8b7a3d2')
  1254. },
  1255. 'a b/c': {
  1256. 'dep_type':
  1257. 'git',
  1258. 'url': ('http://example.com/a%20b/c@' +
  1259. 'b9f77763f0fab67eeeb6371492166567a8b7a3d2'),
  1260. }
  1261. })
  1262. subprocess2_check_output_mock.assert_has_calls([
  1263. mock.call(['git', 'config', '--file', mock.ANY, '-l']),
  1264. mock.call([
  1265. 'git', 'ls-files', '-s', '--', 'foo/bar', 'aaaaaa',
  1266. 'a.a.a/a', 'a_b/c', 'a b/c'
  1267. ],
  1268. cwd=mock.ANY)
  1269. ])
  1270. def testParseGitSubmodules_UsesAbsolutePath(self):
  1271. """ParseGitSubmodules uses absolute path when use_relative_path is not
  1272. set."""
  1273. solutions = [{
  1274. 'name': 'foobar',
  1275. 'url': 'https://example.com/foobar',
  1276. 'deps_file': '.DEPS.git',
  1277. }]
  1278. write('.gclient', 'solutions = %s' % repr(solutions))
  1279. ls_files = """160000 be8c5114d606692dc783b60cf256690b62fbad17 0\tfoo/bar
  1280. 160000 3ad3b564f8ae456f286446d091709f5a09fa4a93 0\taaaaaa
  1281. 160000 956df937508b65b5e72a4cf02696255be3631b78 0\ta.a.a/a
  1282. 160000 b9f77763f0fab67eeeb6371492166567a8b7a3d2 0\ta_b/c
  1283. 160000 b9f77763f0fab67eeeb6371492166567a8b7a3d2 0\ta b/c"""
  1284. git_config = """submodule.foo/bar.path=foo/bar
  1285. submodule.foo/bar.url=http://example.com/foo/bar
  1286. submodule.foo/bar.gclient-condition=checkout_linux
  1287. submodule.aaaaaa.path=aaaaaa
  1288. submodule.aaaaaa.url=http://example.com/aaaaaa
  1289. submodule.a.a.a/a.path=a.a.a/a
  1290. submodule.a.a.a/a.url=http://example.com/a.a.a/a
  1291. submodule.a_b/c.path=a_b/c
  1292. submodule.a_b/c.url=http://example.com/a_b/c
  1293. submodule.a b/c.path=a b/c
  1294. submodule.a b/c.url=http://example.com/a%20b/c"""
  1295. os_path_isfile_mock = mock.MagicMock(return_value=True)
  1296. subprocess2_check_output_mock = mock.MagicMock(
  1297. side_effect=[git_config.encode(),
  1298. ls_files.encode()])
  1299. options, _ = gclient.OptionParser().parse_args([])
  1300. client = gclient.GClient.LoadCurrentConfig(options)
  1301. self.assertEqual(1, len(client.dependencies))
  1302. sol = client.dependencies[0]
  1303. with mock.patch('os.path.isfile', os_path_isfile_mock), mock.patch(
  1304. 'subprocess2.check_output', subprocess2_check_output_mock):
  1305. self.assertEqual(
  1306. sol.ParseGitSubmodules(), {
  1307. 'foobar/foo/bar': {
  1308. 'dep_type':
  1309. 'git',
  1310. 'url': ('http://example.com/foo/bar@' +
  1311. 'be8c5114d606692dc783b60cf256690b62fbad17'),
  1312. 'condition':
  1313. 'checkout_linux',
  1314. },
  1315. 'foobar/aaaaaa': {
  1316. 'dep_type':
  1317. 'git',
  1318. 'url': ('http://example.com/aaaaaa@' +
  1319. '3ad3b564f8ae456f286446d091709f5a09fa4a93'),
  1320. },
  1321. 'foobar/a.a.a/a': {
  1322. 'dep_type':
  1323. 'git',
  1324. 'url': ('http://example.com/a.a.a/a@' +
  1325. '956df937508b65b5e72a4cf02696255be3631b78'),
  1326. },
  1327. 'foobar/a_b/c': {
  1328. 'dep_type':
  1329. 'git',
  1330. 'url': ('http://example.com/a_b/c@' +
  1331. 'b9f77763f0fab67eeeb6371492166567a8b7a3d2')
  1332. },
  1333. 'foobar/a b/c': {
  1334. 'dep_type':
  1335. 'git',
  1336. 'url': ('http://example.com/a%20b/c@' +
  1337. 'b9f77763f0fab67eeeb6371492166567a8b7a3d2'),
  1338. }
  1339. })
  1340. subprocess2_check_output_mock.assert_has_calls([
  1341. mock.call(['git', 'config', '--file', mock.ANY, '-l']),
  1342. mock.call([
  1343. 'git', 'ls-files', '-s', '--', 'foo/bar', 'aaaaaa',
  1344. 'a.a.a/a', 'a_b/c', 'a b/c'
  1345. ],
  1346. cwd=mock.ANY)
  1347. ])
  1348. def testSameDirAllowMultipleCipdDeps(self):
  1349. """Verifies gclient allow multiple cipd deps under same directory."""
  1350. parser = gclient.OptionParser()
  1351. options, _ = parser.parse_args([])
  1352. obj = gclient.GClient('foo', options)
  1353. cipd_root = CIPDRootMock(os.path.join(self.root_dir, 'dir1'),
  1354. 'https://example.com')
  1355. obj.add_dependencies_and_close([
  1356. gclient.Dependency(parent=obj,
  1357. name='foo',
  1358. url='svn://example.com/foo',
  1359. managed=None,
  1360. custom_deps=None,
  1361. custom_vars=None,
  1362. custom_hooks=None,
  1363. deps_file='DEPS',
  1364. should_process=True,
  1365. should_recurse=True,
  1366. relative=False,
  1367. condition=None,
  1368. protocol='https',
  1369. print_outbuf=True),
  1370. ], [])
  1371. obj.dependencies[0].add_dependencies_and_close([
  1372. gclient.CipdDependency(parent=obj.dependencies[0],
  1373. name='foo',
  1374. dep_value={
  1375. 'package': 'foo_package',
  1376. 'version': 'foo_version'
  1377. },
  1378. cipd_root=cipd_root,
  1379. custom_vars=None,
  1380. should_process=True,
  1381. relative=False,
  1382. condition='fake_condition'),
  1383. gclient.CipdDependency(parent=obj.dependencies[0],
  1384. name='bar',
  1385. dep_value={
  1386. 'package': 'bar_package',
  1387. 'version': 'bar_version'
  1388. },
  1389. cipd_root=cipd_root,
  1390. custom_vars=None,
  1391. should_process=True,
  1392. relative=False,
  1393. condition='fake_condition'),
  1394. ], [])
  1395. dep0 = obj.dependencies[0].dependencies[0]
  1396. dep1 = obj.dependencies[0].dependencies[1]
  1397. self.assertEqual('https://example.com/foo_package@foo_version',
  1398. dep0.url)
  1399. self.assertEqual('https://example.com/bar_package@bar_version',
  1400. dep1.url)
  1401. def _testPosixpathImpl(self):
  1402. parser = gclient.OptionParser()
  1403. options, _ = parser.parse_args([])
  1404. obj = gclient.GClient('src', options)
  1405. cipd_root = CIPDRootMock('src', 'https://example.com')
  1406. cipd_dep = gclient.CipdDependency(parent=obj,
  1407. name='src/foo/bar/baz',
  1408. dep_value={
  1409. 'package': 'baz_package',
  1410. 'version': 'baz_version',
  1411. },
  1412. cipd_root=cipd_root,
  1413. custom_vars=None,
  1414. should_process=True,
  1415. relative=False,
  1416. condition=None)
  1417. self.assertEqual(cipd_dep._cipd_subdir, 'src/foo/bar/baz')
  1418. def testPosixpathCipdSubdir(self):
  1419. self._testPosixpathImpl()
  1420. # CIPD wants posixpath separators for subdirs, even on windows.
  1421. # See crbug.com/854219.
  1422. def testPosixpathCipdSubdirOnWindows(self):
  1423. with mock.patch('os.path', new=ntpath), (mock.patch('os.sep',
  1424. new=ntpath.sep)):
  1425. self._testPosixpathImpl()
  1426. def testFuzzyMatchUrlByURL(self):
  1427. write(
  1428. '.gclient', 'solutions = [\n'
  1429. ' { "name": "foo", "url": "https://example.com/foo.git",\n'
  1430. ' "deps_file" : ".DEPS.git",\n'
  1431. ' },\n'
  1432. ']')
  1433. write(
  1434. os.path.join('foo', 'DEPS'), 'deps = {\n'
  1435. ' "bar": "https://example.com/bar.git@bar_version",\n'
  1436. '}')
  1437. options, _ = gclient.OptionParser().parse_args([])
  1438. obj = gclient.GClient.LoadCurrentConfig(options)
  1439. foo_sol = obj.dependencies[0]
  1440. self.assertEqual(
  1441. 'https://example.com/foo.git',
  1442. foo_sol.FuzzyMatchUrl(['https://example.com/foo.git', 'foo']))
  1443. def testFuzzyMatchUrlByURLNoGit(self):
  1444. write(
  1445. '.gclient', 'solutions = [\n'
  1446. ' { "name": "foo", "url": "https://example.com/foo.git",\n'
  1447. ' "deps_file" : ".DEPS.git",\n'
  1448. ' },\n'
  1449. ']')
  1450. write(
  1451. os.path.join('foo', 'DEPS'), 'deps = {\n'
  1452. ' "bar": "https://example.com/bar.git@bar_version",\n'
  1453. '}')
  1454. options, _ = gclient.OptionParser().parse_args([])
  1455. obj = gclient.GClient.LoadCurrentConfig(options)
  1456. foo_sol = obj.dependencies[0]
  1457. self.assertEqual(
  1458. 'https://example.com/foo',
  1459. foo_sol.FuzzyMatchUrl(['https://example.com/foo', 'foo']))
  1460. def testFuzzyMatchUrlByName(self):
  1461. write(
  1462. '.gclient', 'solutions = [\n'
  1463. ' { "name": "foo", "url": "https://example.com/foo",\n'
  1464. ' "deps_file" : ".DEPS.git",\n'
  1465. ' },\n'
  1466. ']')
  1467. write(
  1468. os.path.join('foo', 'DEPS'), 'deps = {\n'
  1469. ' "bar": "https://example.com/bar.git@bar_version",\n'
  1470. '}')
  1471. options, _ = gclient.OptionParser().parse_args([])
  1472. obj = gclient.GClient.LoadCurrentConfig(options)
  1473. foo_sol = obj.dependencies[0]
  1474. self.assertEqual('foo', foo_sol.FuzzyMatchUrl(['foo']))
  1475. def testEnforceSkipSyncRevisions_DepsPatchRefs(self):
  1476. """Patch_refs for any deps removes all skip_sync_revisions."""
  1477. write(
  1478. '.gclient', 'solutions = [\n'
  1479. ' { "name": "foo/src", "url": "https://example.com/foo",\n'
  1480. ' "deps_file" : ".DEPS.git",\n'
  1481. ' },\n'
  1482. ']')
  1483. write(
  1484. os.path.join('foo/src', 'DEPS'), 'deps = {\n'
  1485. ' "bar": "https://example.com/bar.git@bar_version",\n'
  1486. '}')
  1487. write(gclient.PREVIOUS_SYNC_COMMITS_FILE,
  1488. json.dumps({'foo/src': '1234'}))
  1489. options, _ = gclient.OptionParser().parse_args([])
  1490. client = gclient.GClient.LoadCurrentConfig(options)
  1491. patch_refs = {'foo/src': '1222', 'somedeps': '1111'}
  1492. self.assertEqual({}, client._EnforceSkipSyncRevisions(patch_refs))
  1493. def testEnforceSkipSyncRevisions_CustomVars(self):
  1494. """Changes in a sol's custom_vars removes its revisions."""
  1495. write(
  1496. '.gclient', 'solutions = [\n'
  1497. ' { "name": "samevars", "url": "https://example.com/foo",\n'
  1498. ' "deps_file" : ".DEPS.git",\n'
  1499. ' "custom_vars" : { "checkout_foo": "true" },\n'
  1500. ' },\n'
  1501. ' { "name": "diffvars", "url": "https://example.com/chicken",\n'
  1502. ' "deps_file" : ".DEPS.git",\n'
  1503. ' "custom_vars" : { "checkout_chicken": "true" },\n'
  1504. ' },\n'
  1505. ' { "name": "novars", "url": "https://example.com/cow",\n'
  1506. ' "deps_file" : ".DEPS.git",\n'
  1507. ' },\n'
  1508. ']')
  1509. write(
  1510. os.path.join('samevars', 'DEPS'), 'deps = {\n'
  1511. ' "bar": "https://example.com/bar.git@bar_version",\n'
  1512. '}')
  1513. write(
  1514. os.path.join('diffvars', 'DEPS'), 'deps = {\n'
  1515. ' "moo": "https://example.com/moo.git@moo_version",\n'
  1516. '}')
  1517. write(
  1518. os.path.join('novars', 'DEPS'), 'deps = {\n'
  1519. ' "poo": "https://example.com/poo.git@poo_version",\n'
  1520. '}')
  1521. previous_custom_vars = {
  1522. 'samevars': {
  1523. 'checkout_foo': 'true'
  1524. },
  1525. 'diffvars': {
  1526. 'checkout_chicken': 'false'
  1527. },
  1528. }
  1529. write(gclient.PREVIOUS_CUSTOM_VARS_FILE,
  1530. json.dumps(previous_custom_vars))
  1531. previous_sync_commits = {
  1532. 'samevars': '10001',
  1533. 'diffvars': '10002',
  1534. 'novars': '10003'
  1535. }
  1536. write(gclient.PREVIOUS_SYNC_COMMITS_FILE,
  1537. json.dumps(previous_sync_commits))
  1538. options, _ = gclient.OptionParser().parse_args([])
  1539. patch_refs = {'samevars': '1222'}
  1540. expected_skip_sync_revisions = {'samevars': '10001', 'novars': '10003'}
  1541. client = gclient.GClient.LoadCurrentConfig(options)
  1542. self.assertEqual(expected_skip_sync_revisions,
  1543. client._EnforceSkipSyncRevisions(patch_refs))
  1544. class MergeVarsTest(unittest.TestCase):
  1545. def test_merge_vars(self):
  1546. merge_vars = gclient.merge_vars
  1547. Str = gclient_eval.ConstantString
  1548. l = {'foo': 'bar', 'baz': True}
  1549. merge_vars(l, {'foo': Str('quux')})
  1550. self.assertEqual(l, {'foo': 'quux', 'baz': True})
  1551. l = {'foo': 'bar', 'baz': True}
  1552. merge_vars(l, {'foo': 'quux'})
  1553. self.assertEqual(l, {'foo': 'quux', 'baz': True})
  1554. l = {'foo': Str('bar'), 'baz': True}
  1555. merge_vars(l, {'foo': Str('quux')})
  1556. self.assertEqual(l, {'foo': Str('quux'), 'baz': True})
  1557. l = {'foo': Str('bar'), 'baz': True}
  1558. merge_vars(l, {'foo': Str('quux')})
  1559. self.assertEqual(l, {'foo': Str('quux'), 'baz': True})
  1560. l = {'foo': 'bar'}
  1561. merge_vars(l, {'baz': True})
  1562. self.assertEqual(l, {'foo': 'bar', 'baz': True})
  1563. if __name__ == '__main__':
  1564. sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout)
  1565. sys.stdout = gclient_utils.MakeFileAnnotated(sys.stdout)
  1566. sys.stderr = gclient_utils.MakeFileAutoFlush(sys.stderr)
  1567. sys.stderr = gclient_utils.MakeFileAnnotated(sys.stderr)
  1568. logging.basicConfig(
  1569. level=[logging.ERROR, logging.WARNING, logging.INFO,
  1570. logging.DEBUG][min(sys.argv.count('-v'), 3)],
  1571. format='%(relativeCreated)4d %(levelname)5s %(module)13s('
  1572. '%(lineno)d) %(message)s')
  1573. unittest.main()