]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Allow init into existing but empty directory
authorAviskar KC <aviskarkc10@gmail.com>
Thu, 4 Jul 2019 18:31:03 +0000 (14:31 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 18 Jul 2019 18:26:20 +0000 (14:26 -0400)
The "alembic init" command will now proceed if the target directory exists
as long as it's still empty.  Previously, it would not proceed if the
directory existed. The new behavior is modeled from what git does, to
accommodate for container or other deployments where an Alembic target
directory may need to be already mounted instead of being created with
alembic init.  Pull request courtesy Aviskar KC.

Fixes: #571
Closes: #574
Pull-request: https://github.com/sqlalchemy/alembic/pull/574
Pull-request-sha: ab7b8f342a89c752460d171cd50d1f958c7d59c9

Change-Id: I6b0cff9a7e940d9d878aa339891bda33744a2a4c

alembic/command.py
docs/build/unreleased/571.rst [new file with mode: 0644]
tests/test_command.py

index 3faafddfb337ca826249d6bc4b2144d38f5f547c..c02db62a8d7d0111040ad6b09f9bc918238f0fa1 100644 (file)
@@ -37,18 +37,21 @@ def init(config, directory, template="generic"):
 
     """
 
-    if os.access(directory, os.F_OK):
-        raise util.CommandError("Directory %s already exists" % directory)
+    if os.access(directory, os.F_OK) and os.listdir(directory):
+        raise util.CommandError(
+            "Directory %s already exists and is not empty" % directory
+        )
 
     template_dir = os.path.join(config.get_template_directory(), template)
     if not os.access(template_dir, os.F_OK):
         raise util.CommandError("No such template %r" % template)
 
-    util.status(
-        "Creating directory %s" % os.path.abspath(directory),
-        os.makedirs,
-        directory,
-    )
+    if not os.access(directory, os.F_OK):
+        util.status(
+            "Creating directory %s" % os.path.abspath(directory),
+            os.makedirs,
+            directory,
+        )
 
     versions = os.path.join(directory, "versions")
     util.status(
diff --git a/docs/build/unreleased/571.rst b/docs/build/unreleased/571.rst
new file mode 100644 (file)
index 0000000..82c7647
--- /dev/null
@@ -0,0 +1,12 @@
+.. change::
+    :tags: usecase, commands
+    :tickets: 571
+
+    The "alembic init" command will now proceed if the target directory exists
+    as long as it's still empty.  Previously, it would not proceed if the
+    directory existed. The new behavior is modeled from what git does, to
+    accommodate for container or other deployments where an Alembic target
+    directory may need to be already mounted instead of being created with
+    alembic init.  Pull request courtesy Aviskar KC.
+
+
index 653028ff7f034697f2bf63f09a853cbe7a2392fd..746471be446b7b4b1da6652357e5de2bd00d1a85 100644 (file)
@@ -800,3 +800,57 @@ class CommandLineTest(TestBase):
                             # not too long
                             assert len(help_text) < 80
         assert not commands, "Commands without help text: %s" % commands
+
+    def test_init_file_exists_and_is_not_empty(self):
+        with mock.patch(
+            "alembic.command.os.listdir", return_value=["file1", "file2"]
+        ), mock.patch("alembic.command.os.access", return_value=True):
+            directory = "alembic"
+            assert_raises_message(
+                util.CommandError,
+                "Directory %s already exists and is not empty" % directory,
+                command.init,
+                self.cfg,
+                directory=directory,
+            )
+
+    def test_init_file_exists_and_is_empty(self):
+        def access_(path, mode):
+            if "generic" in path or path == "foobar":
+                return True
+            else:
+                return False
+
+        def listdir_(path):
+            if path == "foobar":
+                return []
+            else:
+                return ["file1", "file2", "alembic.ini.mako"]
+
+        with mock.patch(
+            "alembic.command.os.access", side_effect=access_
+        ), mock.patch("alembic.command.os.makedirs") as makedirs, mock.patch(
+            "alembic.command.os.listdir", side_effect=listdir_
+        ), mock.patch(
+            "alembic.command.ScriptDirectory"
+        ):
+            command.init(self.cfg, directory="foobar")
+            eq_(makedirs.mock_calls, [mock.call("foobar/versions")])
+
+    def test_init_file_doesnt_exist(self):
+        def access_(path, mode):
+            if "generic" in path:
+                return True
+            else:
+                return False
+
+        with mock.patch(
+            "alembic.command.os.access", side_effect=access_
+        ), mock.patch("alembic.command.os.makedirs") as makedirs, mock.patch(
+            "alembic.command.ScriptDirectory"
+        ):
+            command.init(self.cfg, directory="foobar")
+            eq_(
+                makedirs.mock_calls,
+                [mock.call("foobar"), mock.call("foobar/versions")],
+            )