浏览代码

Ability to change working directory via a CLI flag

Signed-off-by: Dimitar Bonev <[email protected]>
Dimitar Bonev 9 年之前
父节点
当前提交
707210ae95

+ 4 - 3
compose/cli/command.py

@@ -33,7 +33,8 @@ def project_from_options(project_dir, options):
         verbose=options.get('--verbose'),
         verbose=options.get('--verbose'),
         host=host,
         host=host,
         tls_config=tls_config_from_options(options),
         tls_config=tls_config_from_options(options),
-        environment=environment
+        environment=environment,
+        override_dir=options.get('--project-directory'),
     )
     )
 
 
 
 
@@ -93,10 +94,10 @@ def get_client(environment, verbose=False, version=None, tls_config=None, host=N
 
 
 
 
 def get_project(project_dir, config_path=None, project_name=None, verbose=False,
 def get_project(project_dir, config_path=None, project_name=None, verbose=False,
-                host=None, tls_config=None, environment=None):
+                host=None, tls_config=None, environment=None, override_dir=None):
     if not environment:
     if not environment:
         environment = Environment.from_env_file(project_dir)
         environment = Environment.from_env_file(project_dir)
-    config_details = config.find(project_dir, config_path, environment)
+    config_details = config.find(project_dir, config_path, environment, override_dir)
     project_name = get_project_name(
     project_name = get_project_name(
         config_details.working_dir, project_name, environment
         config_details.working_dir, project_name, environment
     )
     )

+ 2 - 0
compose/cli/main.py

@@ -168,6 +168,8 @@ class TopLevelCommand(object):
       --skip-hostname-check       Don't check the daemon's hostname against the name specified
       --skip-hostname-check       Don't check the daemon's hostname against the name specified
                                   in the client certificate (for example if your docker host
                                   in the client certificate (for example if your docker host
                                   is an IP address)
                                   is an IP address)
+      --project-directory PATH    Specify an alternate working directory
+                                  (default: the path of the compose file)
 
 
     Commands:
     Commands:
       build              Build or rebuild services
       build              Build or rebuild services

+ 3 - 3
compose/config/config.py

@@ -235,10 +235,10 @@ class ServiceConfig(namedtuple('_ServiceConfig', 'working_dir filename name conf
             config)
             config)
 
 
 
 
-def find(base_dir, filenames, environment):
+def find(base_dir, filenames, environment, override_dir='.'):
     if filenames == ['-']:
     if filenames == ['-']:
         return ConfigDetails(
         return ConfigDetails(
-            os.getcwd(),
+            os.path.abspath(override_dir),
             [ConfigFile(None, yaml.safe_load(sys.stdin))],
             [ConfigFile(None, yaml.safe_load(sys.stdin))],
             environment
             environment
         )
         )
@@ -250,7 +250,7 @@ def find(base_dir, filenames, environment):
 
 
     log.debug("Using configuration files: {}".format(",".join(filenames)))
     log.debug("Using configuration files: {}".format(",".join(filenames)))
     return ConfigDetails(
     return ConfigDetails(
-        os.path.dirname(filenames[0]),
+        override_dir or os.path.dirname(filenames[0]),
         [ConfigFile.from_filename(f) for f in filenames],
         [ConfigFile.from_filename(f) for f in filenames],
         environment
         environment
     )
     )

+ 19 - 1
tests/acceptance/cli_test.py

@@ -107,6 +107,7 @@ class CLITestCase(DockerClientTestCase):
     def setUp(self):
     def setUp(self):
         super(CLITestCase, self).setUp()
         super(CLITestCase, self).setUp()
         self.base_dir = 'tests/fixtures/simple-composefile'
         self.base_dir = 'tests/fixtures/simple-composefile'
+        self.override_dir = None
 
 
     def tearDown(self):
     def tearDown(self):
         if self.base_dir:
         if self.base_dir:
@@ -129,7 +130,7 @@ class CLITestCase(DockerClientTestCase):
     def project(self):
     def project(self):
         # Hack: allow project to be overridden
         # Hack: allow project to be overridden
         if not hasattr(self, '_project'):
         if not hasattr(self, '_project'):
-            self._project = get_project(self.base_dir)
+            self._project = get_project(self.base_dir, override_dir=self.override_dir)
         return self._project
         return self._project
 
 
     def dispatch(self, options, project_options=None, returncode=0):
     def dispatch(self, options, project_options=None, returncode=0):
@@ -518,6 +519,23 @@ class CLITestCase(DockerClientTestCase):
             },
             },
         }
         }
 
 
+    def test_build_override_dir(self):
+        self.base_dir = 'tests/fixtures/build-path-override-dir'
+        self.override_dir = os.path.abspath('tests/fixtures')
+        result = self.dispatch([
+            '--project-directory', self.override_dir,
+            'build'])
+
+        assert 'Successfully built' in result.stdout
+
+    def test_build_override_dir_invalid_path(self):
+        config_path = os.path.abspath('tests/fixtures/build-path-override-dir/docker-compose.yml')
+        result = self.dispatch([
+            '-f', config_path,
+            'build'], returncode=1)
+
+        assert 'does not exist, is not accessible, or is not a valid URL' in result.stderr
+
     def test_create(self):
     def test_create(self):
         self.dispatch(['create'])
         self.dispatch(['create'])
         service = self.project.get_service('simple')
         service = self.project.get_service('simple')

+ 2 - 0
tests/fixtures/build-path-override-dir/docker-compose.yml

@@ -0,0 +1,2 @@
+foo:
+  build: ./build-ctx/

+ 8 - 2
tests/unit/config/config_test.py

@@ -2875,9 +2875,9 @@ class EnvTest(unittest.TestCase):
             set([VolumeSpec.parse('/opt/tmp:/opt/host/tmp')]))
             set([VolumeSpec.parse('/opt/tmp:/opt/host/tmp')]))
 
 
 
 
-def load_from_filename(filename):
+def load_from_filename(filename, override_dir=None):
     return config.load(
     return config.load(
-        config.find('.', [filename], Environment.from_env_file('.'))
+        config.find('.', [filename], Environment.from_env_file('.'), override_dir=override_dir)
     ).services
     ).services
 
 
 
 
@@ -3443,6 +3443,12 @@ class BuildPathTest(unittest.TestCase):
         service_dict = load_from_filename('tests/fixtures/build-path/docker-compose.yml')
         service_dict = load_from_filename('tests/fixtures/build-path/docker-compose.yml')
         self.assertEqual(service_dict, [{'name': 'foo', 'build': {'context': self.abs_context_path}}])
         self.assertEqual(service_dict, [{'name': 'foo', 'build': {'context': self.abs_context_path}}])
 
 
+    def test_from_file_override_dir(self):
+        override_dir = os.path.join(os.getcwd(), 'tests/fixtures/')
+        service_dict = load_from_filename(
+            'tests/fixtures/build-path-override-dir/docker-compose.yml', override_dir=override_dir)
+        self.assertEquals(service_dict, [{'name': 'foo', 'build': {'context': self.abs_context_path}}])
+
     def test_valid_url_in_build_path(self):
     def test_valid_url_in_build_path(self):
         valid_urls = [
         valid_urls = [
             'git://github.com/docker/docker',
             'git://github.com/docker/docker',