diff --git a/gclient_utils.py b/gclient_utils.py index 04767974e..d21ade51b 100644 --- a/gclient_utils.py +++ b/gclient_utils.py @@ -348,12 +348,39 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, def FindGclientRoot(from_dir, filename='.gclient'): """Tries to find the gclient root.""" - path = os.path.realpath(from_dir) + real_from_dir = os.path.realpath(from_dir) + path = real_from_dir while not os.path.exists(os.path.join(path, filename)): split_path = os.path.split(path) if not split_path[1]: return None path = split_path[0] + + # If we did not find the file in the current directory, make sure we are in a + # sub directory that is controlled by this configuration. + if path != real_from_dir: + entries_filename = os.path.join(path, filename + '_entries') + if not os.path.exists(entries_filename): + # If .gclient_entries does not exist, a previous call to gclient sync + # might have failed. In that case, we cannot verify that the .gclient + # is the one we want to use. In order to not to cause too much trouble, + # just issue a warning and return the path anyway. + print >>sys.stderr, ("%s file in parent directory %s might not be the " + "file you want to use" % (filename, path)) + return path + scope = {} + try: + exec(FileRead(entries_filename), scope) + except SyntaxError, e: + SyntaxErrorToError(filename, e) + all_directories = scope['entries'].keys() + path_to_check = real_from_dir[len(path)+1:] + while path_to_check: + if path_to_check in all_directories: + return path + path_to_check = os.path.dirname(path_to_check) + return None + logging.info('Found gclient root at ' + path) return path diff --git a/tests/gclient_smoketest.py b/tests/gclient_smoketest.py index bb877cd5f..29913e27f 100755 --- a/tests/gclient_smoketest.py +++ b/tests/gclient_smoketest.py @@ -214,6 +214,19 @@ class GClientSmoke(GClientSmokeBase): self.assertTree({}) self.check(('', '', 0), self.gclient(['status'])) + def testDifferentTopLevelDirectory(self): + # Check that even if the .gclient file does not mention the directory src + # itself, but it is included via dependencies, the .gclient file is used. + self.gclient(['config', self.svn_base + 'trunk/src.DEPS']) + deps = join(self.root_dir, 'src.DEPS') + os.mkdir(deps) + write(join(deps, 'DEPS'), + 'deps = { "src": "%strunk/src" }' % (self.svn_base)) + src = join(self.root_dir, 'src') + os.mkdir(src) + res = self.gclient(['status'], src) + self.checkBlock(res[0], [('running', deps), ('running', src)]) + class GClientSmokeSVN(GClientSmokeBase): def setUp(self): @@ -461,6 +474,48 @@ class GClientSmokeSVN(GClientSmokeBase): { 'base': self.svn_base + 'trunk' }) self.check((out, '', 0), results) + def testWrongDirectory(self): + # Check that we're not using a .gclient configuration which only talks + # about a subdirectory src when we're in a different subdirectory src-other. + self.gclient(['config', self.svn_base + 'trunk/src/']) + self.gclient(['sync']) + other_src = join(self.root_dir, 'src-other') + os.mkdir(other_src) + res = ('', 'Error: client not configured; see \'gclient config\'\n', 1) + self.check(res, self.gclient(['status'], other_src)) + + def testCorrectDirectory(self): + # Check that when we're in the subdirectory src, the .gclient configuration + # is used. + self.gclient(['config', self.svn_base + 'trunk/src/']) + self.gclient(['sync']) + src = join(self.root_dir, 'src') + res = self.gclient(['status'], src) + self.checkBlock(res[0], [('running', src)]) + + def testInitialCheckoutNotYetDone(self): + # Check that gclient can be executed when the initial checkout hasn't been + # done yet. + self.gclient(['config', self.svn_base + 'trunk/src/']) + self.parseGclient(['sync'], + ['running', 'running', + # This is due to the way svn update is called for a + # single file when File() is used in a DEPS file. + ('running', self.root_dir + '/src/file/other'), + 'running', 'running', 'running', 'running']) + + def testInitialCheckoutFailed(self): + # Check that gclient can be executed from an arbitrary sub directory if the + # initial checkout has failed. + self.gclient(['config', self.svn_base + 'trunk/src/']) + self.gclient(['sync']) + # Cripple the checkout. + os.remove(join(self.root_dir, '.gclient_entries')) + src = join(self.root_dir, 'src') + res = self.gclient(['sync'], src) + self.checkBlock(res[0], + ['running', 'running', 'running']) + class GClientSmokeGIT(GClientSmokeBase): def setUp(self):