Skip to content

Commit 638fbdd

Browse files
committed
feat!: don't mount code from host directory
Up until now, `restyle` worked by mounting the code directory into the restyler container and letting the fixes occur against those files there. This has always come with some issues: 1. The container may change file ownership to `root` 2. The process may create working or backup files 3. The process needs to know about the host file system in order to mount correctly if `restyle` itself is dockerized (1) was an open issue we've not solved. (2) we solved with a Big Hammer, running `git clean` at the end. And (3) we had solved with a `HOST_DIRECTORY` option, but thankfully no longer needed when we moved to a native `restyle` binary. Attempting to run on Forgejo actions reintroduces (3) because `restyle` is again in a container there. Unfortunately we can't (easily) solve it with `HOST_DIRECTORY` because that path is more volatile and harder to discover than it was on GitHub Actions. Therefore a new solution was implemented. Now, what we do is: 1. Create a docker volume 2. Use a temporary container to fill the volume with the current directory's contents 3. Run all restylers with that volume mounted 4. Use a temporary container to copy out the paths we were attempting to restyle This is a bit of complexity, but at least 1, 2, and 4 occur once and not per restyler. It completely avoids having to have knowledge of the host file system since the `docker cp` commands work with paths where they are even if the process it itself containerized. As a bonus, we avoid the other two other issues: 1. The files are copied out, and so retain correct ownership, instead of being modified in a container as `root` 2. Since we aren't mounting the whole directory, but only copying back out the files we intended to change, we have no issue with dirtying things such that we need or want a `git clean` step
1 parent 868262c commit 638fbdd

File tree

10 files changed

+102
-77
lines changed

10 files changed

+102
-77
lines changed

restyler.cabal

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 1.12
22

3-
-- This file has been generated from package.yaml by hpack version 0.38.0.
3+
-- This file has been generated from package.yaml by hpack version 0.38.1.
44
--
55
-- see: https://github.com/sol/hpack
66

@@ -14,6 +14,7 @@ library
1414
Restyler.AnnotatedException
1515
Restyler.App
1616
Restyler.CLI
17+
Restyler.CodeVolume
1718
Restyler.Config
1819
Restyler.Config.AutoEnable
1920
Restyler.Config.CommitTemplate
@@ -22,7 +23,6 @@ library
2223
Restyler.Config.Exclude
2324
Restyler.Config.FailOnDifferences
2425
Restyler.Config.Glob
25-
Restyler.Config.HostDirectory
2626
Restyler.Config.Ignore
2727
Restyler.Config.Image
2828
Restyler.Config.ImageCleanup

src/Restyler/App.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,9 @@ instance HasDryRun App where getDryRun = (.config.dryRun)
6161
instance HasEnabled App where getEnabled = (.config.enabled)
6262
instance HasExclude App where getExclude = (.config.exclude)
6363
instance HasFailOnDifferences App where getFailOnDifferences = (.config.failOnDifferences)
64-
instance HasHostDirectory App where getHostDirectory = (.config.hostDirectory)
6564
instance HasIgnores App where getIgnores = (.config.ignores)
6665
instance HasImageCleanup App where getImageCleanup = (.config.imageCleanup)
6766
instance HasManifest App where getManifest = (.config.restylersManifest)
68-
instance HasNoClean App where getNoClean = (.config.noClean)
6967
instance HasNoCommit App where getNoCommit = (.config.noCommit)
7068
instance HasNoPull App where getNoPull = (.config.noPull)
7169
instance HasRemoteFiles App where getRemoteFiles = (.config.remoteFiles)

src/Restyler/CodeVolume.hs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- |
2+
--
3+
-- Module : Restyler.CodeVolume
4+
-- Copyright : (c) 2025 Patrick Brisbin
5+
-- License : AGPL-3
6+
-- Maintainer : pbrisbin@gmail.com
7+
-- Stability : experimental
8+
-- Portability : POSIX
9+
module Restyler.CodeVolume
10+
( withCodeVolume
11+
) where
12+
13+
import Restyler.Prelude
14+
15+
import Restyler.Monad.Docker
16+
import UnliftIO.Exception (bracket)
17+
18+
withCodeVolume :: (MonadDocker m, MonadUnliftIO m) => (String -> m a) -> m a
19+
withCodeVolume = bracket acquire dockerVolumeRm
20+
where
21+
acquire :: (MonadDocker m, MonadUnliftIO m) => m String
22+
acquire = withVolumeInContainer tmpVolumeName $ \cName cPath -> do
23+
tmpVolumeName <$ dockerCp "." (cName <> ":" <> cPath)
24+
25+
withVolumeInContainer
26+
:: (MonadDocker m, MonadUnliftIO m)
27+
=> String
28+
-> (String -> FilePath -> m a)
29+
-> m a
30+
withVolumeInContainer name = bracket acquire (dockerRm . fst) . uncurry
31+
where
32+
acquire :: MonadDocker m => m (String, FilePath)
33+
acquire = do
34+
dockerCreate
35+
$ ["--name", tmpContainerName]
36+
<> ["--volume", name <> ":" <> tmpContainerPath]
37+
<> ["busybox"]
38+
39+
pure (tmpContainerName, tmpContainerPath)
40+
41+
tmpVolumeName :: String
42+
tmpVolumeName = "restyler-code-volume"
43+
44+
tmpContainerName :: String
45+
tmpContainerName = "restyler-tmp-container"
46+
47+
tmpContainerPath :: FilePath
48+
tmpContainerPath = "/data"

src/Restyler/Config.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import Restyler.Config.Enabled as X
2929
import Restyler.Config.Exclude as X
3030
import Restyler.Config.FailOnDifferences as X
3131
import Restyler.Config.Glob
32-
import Restyler.Config.HostDirectory as X
3332
import Restyler.Config.Ignore as X
3433
import Restyler.Config.ImageCleanup as X
3534
import Restyler.Config.LogSettings as X
@@ -51,7 +50,6 @@ data Config = Config
5150
, restylerOverrides :: [RestylerOverride]
5251
, ignores :: Ignores
5352
, remoteFiles :: [RemoteFile]
54-
, hostDirectory :: Path Abs Dir
5553
, imageCleanup :: Bool
5654
, noPull :: Bool
5755
, restrictions :: Restrictions
@@ -87,7 +85,6 @@ configParser sources =
8785
exclude <- excludeParser
8886
ignores <- ignoresParser
8987
remoteFiles <- remoteFilesParser
90-
hostDirectory <- subConfig_ "docker" hostDirectoryParser
9188
imageCleanup <- subConfig_ "docker" imageCleanupParser
9289
noPull <- subConfig_ "docker" noPullParser
9390
restrictions <- subConfig_ "docker" $ subAll "restyler" restrictionsParser

src/Restyler/Config/HostDirectory.hs

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/Restyler/Config/NoClean.hs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,21 @@
77
-- Stability : experimental
88
-- Portability : POSIX
99
module Restyler.Config.NoClean
10-
( HasNoClean (..)
11-
, noCleanParser
10+
( noCleanParser
1211
) where
1312

1413
import Restyler.Prelude
1514

1615
import OptEnvConf
1716

18-
class HasNoClean env where
19-
getNoClean :: env -> Bool
20-
2117
noCleanParser :: Parser Bool
2218
noCleanParser =
2319
not
2420
<$> withDefault
2521
False
2622
( yesNoSwitch
27-
[ help "Run git-clean after restyling"
23+
[ help "Unused"
2824
, name "clean"
25+
, hidden
2926
]
3027
)

src/Restyler/Monad/Docker.hs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ import System.Process.Typed
2424

2525
class Monad m => MonadDocker m where
2626
dockerPull :: HasCallStack => String -> m ExitCode
27+
dockerCreate :: HasCallStack => [String] -> m ()
2728
dockerRun :: HasCallStack => [String] -> m ExitCode
2829
dockerRunStdout :: HasCallStack => [String] -> m (ExitCode, Text)
2930
dockerImageRm :: HasCallStack => String -> m ()
31+
dockerVolumeCreate :: HasCallStack => String -> m ()
32+
dockerVolumeRm :: HasCallStack => String -> m ()
33+
dockerCp :: String -> String -> m ()
34+
dockerRm :: String -> m ()
3035

3136
-- | An instance that invokes the real @docker@
3237
newtype ActualDocker m a = ActualDocker
@@ -47,9 +52,14 @@ instance
4752
=> MonadDocker (ActualDocker m)
4853
where
4954
dockerPull image = runDocker ["pull", "--quiet", image]
50-
dockerRun args = runDocker $ ["run", "--rm"] <> args
51-
dockerRunStdout args = runDockerStdout $ ["run", "--rm"] <> args
55+
dockerCreate args = runDocker_ $ ["create", "--quiet"] <> args
56+
dockerRun args = runDocker $ ["run"] <> args
57+
dockerRunStdout args = runDockerStdout $ ["run"] <> args
5258
dockerImageRm image = runDocker_ ["image", "rm", "--force", image]
59+
dockerVolumeCreate name = runDocker_ ["volume", "create", "--quiet", name]
60+
dockerVolumeRm name = runDocker_ ["volume", "rm", name]
61+
dockerCp src dst = runDocker_ ["cp", "--quiet", src, dst]
62+
dockerRm name = runDocker_ ["rm", name]
5363

5464
runDocker
5565
:: (HasCallStack, HasLogger env, MonadLogger m, MonadReader env m, MonadUnliftIO m)
@@ -86,6 +96,11 @@ newtype NullDocker m a = NullDocker
8696

8797
instance Monad m => MonadDocker (NullDocker m) where
8898
dockerPull _ = pure ExitSuccess
99+
dockerCreate _ = pure ()
89100
dockerRun _ = pure ExitSuccess
90101
dockerRunStdout _ = pure (ExitSuccess, "")
91102
dockerImageRm _ = pure ()
103+
dockerVolumeCreate _ = pure ()
104+
dockerVolumeRm _ = pure ()
105+
dockerCp _ _ = pure ()
106+
dockerRm _ = pure ()

src/Restyler/Monad/Git.hs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ class Monad m => MonadGit m where
2626
isGitRepository :: HasCallStack => m Bool
2727
gitDiffNameOnly :: HasCallStack => Maybe String -> m [FilePath]
2828
gitCommit :: HasCallStack => String -> NonEmpty FilePath -> m String
29-
gitClean :: HasCallStack => m ()
3029
gitResetHard :: HasCallStack => String -> m ()
3130

3231
-- | An instance that invokes the real @git@
@@ -52,12 +51,6 @@ instance
5251
gitCommit msg paths = do
5352
runGit_ $ ["commit", "--message", msg, "--"] <> toList paths
5453
readGitChomp ["rev-parse", "HEAD"]
55-
gitClean = do
56-
ec <- runGitExitCode ["clean", "-d", "--force"]
57-
when (ec /= ExitSuccess)
58-
$ logWarn
59-
$ "git clean not successful"
60-
:# ["exitCode" .= show @Text ec]
6154
gitResetHard ref = runGit_ ["reset", "--hard", ref]
6255

6356
runGit_
@@ -131,5 +124,4 @@ instance Monad m => MonadGit (NullGit m) where
131124
isGitRepository = pure False
132125
gitDiffNameOnly _ = pure []
133126
gitCommit _ _ = pure ""
134-
gitClean = pure ()
135127
gitResetHard _ = pure ()

src/Restyler/Restyle.hs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ run
3535
, HasDryRun env
3636
, HasEnabled env
3737
, HasExclude env
38-
, HasHostDirectory env
3938
, HasIgnores env
4039
, HasImageCleanup env
4140
, HasLabelNames pr
4241
, HasManifest env
43-
, HasNoClean env
4442
, HasNoCommit env
4543
, HasNoPull env
4644
, HasPullRequestState pr
@@ -92,7 +90,4 @@ run pr paths = do
9290
, "sha" .= result.sha
9391
]
9492

95-
noClean <- asks $ (||) <$> getDryRun <*> getNoClean
96-
unless noClean gitClean
97-
9893
pure $ maybe RestyleNoDifference (const RestyleDifference) mresults

0 commit comments

Comments
 (0)