diff --git a/src/shiv/builder.py b/src/shiv/builder.py index f1f89e3..c3bd387 100644 --- a/src/shiv/builder.py +++ b/src/shiv/builder.py @@ -116,6 +116,9 @@ def create_archive( timestamp = datetime.strptime(env.built_at, BUILD_AT_TIMESTAMP_FORMAT).replace(tzinfo=timezone.utc).timestamp() zipinfo_datetime: Tuple[int, int, int, int, int, int] = time.gmtime(int(timestamp))[0:6] + # Create leading directories when -o points into a missing path (#231). + target.parent.mkdir(parents=True, exist_ok=True) + with target.open(mode="wb") as fd: # Write shebang. diff --git a/test/test_builder.py b/test/test_builder.py index ec5af35..ac4482a 100644 --- a/test/test_builder.py +++ b/test/test_builder.py @@ -64,6 +64,15 @@ def test_create_archive(self, sp, env): with pytest.raises(ZipAppError): create_archive(sp, target, sys.executable, "alsjdbas,,,", env) + + def test_create_archive_creates_missing_parent_dirs(self, sp, env): + """-o into a missing directory must create parents (#231).""" + with tempfile.TemporaryDirectory() as tmpdir: + target = Path(tmpdir, "nested", "out", "test.zip") + assert not target.parent.exists() + create_archive(sp, target, sys.executable, "code:interact", env) + assert zipfile.is_zipfile(str(target)) + @pytest.mark.skipif(os.name == "nt", reason="windows has no concept of execute permissions") def test_archive_permissions(self, sp, env): with tempfile.TemporaryDirectory() as tmpdir: