Skip to content

Commit 063fd5f

Browse files
committed
Detect changes in local files
1 parent cac90ed commit 063fd5f

File tree

19 files changed

+251
-22
lines changed

19 files changed

+251
-22
lines changed

bootstrap/src/Cache.purs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Whine.Bootstrap.Cache
22
( cacheDir
3+
, dependenciesChanged
34
, hashConfig
45
, rebuildCache
56
, whineCorePackage
@@ -10,12 +11,17 @@ import Whine.Runner.Prelude
1011

1112
import Codec.JSON.DecodeError as DecodeError
1213
import Control.Monad.Reader (asks)
14+
import Data.DateTime (DateTime)
15+
import Data.Formatter.DateTime as Fmt
16+
import Data.List as List
1317
import Data.Map as Map
1418
import Data.Maybe (fromJust)
1519
import Data.String as String
1620
import Data.Tuple (uncurry)
21+
import Data.UUID as UUID
1722
import JSON as JSON
1823
import Node.ChildProcess.Types as StdIO
24+
import Node.Path as NodePath
1925
import Partial.Unsafe (unsafePartial)
2026
import Spago.Generated.BuildInfo as BuildInfo
2127
import Whine.Bootstrap.Execa (execResultSuccessOrDie, execSuccessOrDie_, execa)
@@ -37,7 +43,9 @@ rebuildCache { rulePackages, bundleFile } = do
3743
logInfo "Please hold on, preparing to whine..."
3844
logInfo "Applying artificial tears..."
3945

40-
let mainModule = "Main"
46+
unique <- liftEffect $ String.replaceAll (Pattern "-") (Replacement "") <$> UUID.toString <$> UUID.genUUID
47+
48+
let mainModule = "Main" <> unique
4149
packageName = "whine-cached-bootstrap"
4250
dependencies = Map.union rulePackages (uncurry Map.singleton whineCorePackage)
4351

@@ -110,7 +118,7 @@ rebuildCache { rulePackages, bundleFile } = do
110118

111119
logSameLine "Revisiting complaints..."
112120
execSuccessOrDie_ "spago bundle" =<<
113-
execa "npx" ["spago", "bundle"] _
121+
execa "npx" ["spago", "bundle", "--source-maps"] _
114122
{ cwd = Just cacheDir
115123
, stdout = Just StdIO.pipe
116124
, stderr = Just StdIO.pipe
@@ -189,6 +197,44 @@ hashConfig { rulePackages } = hashString $ fold
189197
PackageVersion v -> formatVersion v
190198
LocalPackage p -> p.path <> ":" <> fromMaybe "" p.module
191199

200+
dependenciesChanged :: FilePath -> FilePath -> RunnerM Boolean
201+
dependenciesChanged cwd mapFile = do
202+
logDebug $ "Checking dependency timestamps based on " <> mapFile
203+
readMapFile >>= case _ of
204+
Nothing -> do
205+
logDebug $ mapFile <> " doesn't exist. Assuming dependencies have changed."
206+
pure true
207+
Just { sources } -> do
208+
let cleanSources = sources # filter (not ignored)
209+
{ modifiedTime: mapFileTime } <- FS.stat mapFilePath
210+
211+
fileStats <- for cleanSources \source -> FS.stat (cwd <> "/" <> source) <#> _.modifiedTime <#> (source /\ _)
212+
let mLatestSource = maximumBy (comparing snd) fileStats
213+
214+
logDebug $ fold
215+
[ mapFile, " last modified at", formatTime mapFileTime
216+
, ", latest dependency ", maybe "<none>" fst mLatestSource
217+
, " time is ", maybe "<none>" (formatTime <<< snd) mLatestSource
218+
]
219+
pure $ mLatestSource # maybe true \(_ /\ t) -> mapFileTime < t
220+
where
221+
mapFilePath = cwd <> "/" <> mapFile
222+
223+
readMapFile =
224+
ifM (FS.exists mapFilePath)
225+
(Just <$> (decodeMapFile =<< FS.readFile mapFilePath))
226+
(pure Nothing)
227+
228+
decodeMapFile content = rightOrDie do
229+
json <- JSON.parse content
230+
J.decode sourceMapCodec json # lmap DecodeError.print
231+
232+
ignored file =
233+
head (String.split (Pattern NodePath.sep) file) # maybe false (_ `elem` ignore)
234+
235+
ignore =
236+
["node_modules", "<stdin>", ".spago"]
237+
192238
type SpagoYaml =
193239
{ package ::
194240
{ name :: String
@@ -220,3 +266,23 @@ moduleGraphCodec :: J.Codec (Map String { package :: String })
220266
moduleGraphCodec = J.strMap $ J.object
221267
{ package: J.string
222268
}
269+
270+
sourceMapCodec :: J.Codec { sources :: Array String }
271+
sourceMapCodec = J.object { sources: J.array J.string }
272+
273+
formatTime :: DateTime -> String
274+
formatTime = Fmt.format $ List.fromFoldable
275+
[ Fmt.YearFull
276+
, Fmt.Placeholder "-"
277+
, Fmt.MonthTwoDigits
278+
, Fmt.Placeholder "-"
279+
, Fmt.DayOfMonthTwoDigits
280+
, Fmt.Placeholder "T"
281+
, Fmt.Hours24
282+
, Fmt.Placeholder ":"
283+
, Fmt.MinutesTwoDigits
284+
, Fmt.Placeholder ":"
285+
, Fmt.SecondsTwoDigits
286+
, Fmt.Placeholder "."
287+
, Fmt.Milliseconds
288+
]

bootstrap/src/Main.purs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Node.ChildProcess.Types as StdIO
1313
import Node.Process (argv)
1414
import Node.Process as Node
1515
import Spago.Generated.BuildInfo as BuildInfo
16-
import Whine.Bootstrap.Cache (cacheDir, hashConfig, rebuildCache, whineCorePackage)
16+
import Whine.Bootstrap.Cache (cacheDir, dependenciesChanged, hashConfig, rebuildCache, whineCorePackage)
1717
import Whine.Bootstrap.Execa (execa)
1818
import Whine.Bootstrap.JsonCodecs as J
1919
import Whine.Runner.Cli as Cli
@@ -52,8 +52,17 @@ entryPoint = do
5252
let configHash = hashConfig { rulePackages }
5353
bundleFile = "bundle-" <> configHash <> ".mjs"
5454
bundlePath = cacheDir <> "/" <> bundleFile
55+
bundleSourceMapFile = bundleFile <> ".map"
5556

56-
unlessM (FS.exists bundlePath) $
57+
whenM (dependenciesChanged cacheDir bundleSourceMapFile) do
58+
logDebug "Some source dependencies of the cached bundle have changed"
59+
whenM (FS.exists bundlePath) $
60+
FS.unlink bundlePath
61+
whenM (FS.exists $ cacheDir <> "/" <> bundleSourceMapFile) $
62+
FS.unlink $ cacheDir <> "/" <> bundleSourceMapFile
63+
64+
unlessM (FS.exists bundlePath) do
65+
logDebug "Rebuilding the cached bundle"
5766
rebuildCache { rulePackages, bundleFile }
5867

5968
unlessM (FS.exists bundlePath) $

dist/npm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "whine",
3-
"version": "0.0.27",
3+
"version": "0.0.28",
44
"description": "PureScript linter, extensible, with configurable rules, and one-off escape hatches",
55
"keywords": ["purescript", "lint"],
66
"author": "Fyodor Soikin <name.fa@gmail.com>",

dist/vscode-extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"publisher": "collegevine",
44
"displayName": "Whine at PureScript",
55
"description": "PureScript linter, extensible, with configurable rules, and one-off escape hatches",
6-
"version": "0.0.27",
6+
"version": "0.0.28",
77
"repository": "https://github.com/collegevine/purescript-whine",
88
"engines": {
99
"vscode": "^1.95.0"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Local rule configured with 'null' is running on Local.WhineRules
2+
Local rule configured with 'null' is running on Main
3+
No violations found.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package:
2+
name: test-package
3+
dependencies:
4+
- prelude
5+
- effect
6+
- whine-core
7+
workspace:
8+
packageSet:
9+
registry: 62.2.5
10+
extraPackages:
11+
whine-core:
12+
path: PROJECT_PATH
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect (Effect)
5+
6+
main :: Effect Unit
7+
main = pure unit
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module Local.WhineRules where
2+
3+
import Prelude
4+
5+
import Data.Codec.JSON as CJ
6+
import JSON (JSON)
7+
import JSON as JSON
8+
import PureScript.CST.Types (Module(..), ModuleHeader(..), ModuleName(..), Name(..))
9+
import Whine.Log (logInfo)
10+
import Whine.Types (Handle(..), Rule, RuleFactories, currentModule, emptyRule, ruleFactory)
11+
12+
rules :: RuleFactories
13+
rules = [ruleFactory "LocalRule" CJ.json localRule]
14+
15+
localRule :: JSON -> Rule
16+
localRule config = emptyRule { onModule = onModule }
17+
where
18+
onModule :: Handle Module
19+
onModule = Handle \_ ->
20+
currentModule \(Module { header: ModuleHeader { name: Name { name: ModuleName n } } }) -> do
21+
logInfo $ "Local rule configured with '" <> JSON.print config <> "' is running on " <> n
22+
pure unit
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
rulePackages:
2+
- whine-core:
3+
local: PROJECT_PATH
4+
module: Whine.Core.WhineRules
5+
- local-rules:
6+
local: ./
7+
module: Local.WhineRules
8+
9+
rules:
10+
LocalRule:
11+
foo: "bar"
12+
baz: 42
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
rulePackages:
2+
- whine-core:
3+
local: PROJECT_PATH
4+
module: Whine.Core.WhineRules
5+
- local-rules:
6+
local: ./
7+
module: Local.WhineRules

0 commit comments

Comments
 (0)