Причиной этой проблемы является то, что стек использует метку времени (как и многие другие инструменты), чтобы выяснить, изменился ли исходный файл или нет. Когда вы восстанавливаете кэш на CI и делаете это правильно, ни одна из зависимостей не будет восстановлена, но проблема с исходными файлами состоит в том, что, когда поставщик CI клонирует для вас репо, устанавливаются временные метки для всех файлов в репо. к дате и времени, когда он был клонирован.
Надеемся, что причина для перекомпиляции неизмененных исходных файлов теперь имеет смысл. Что мы делаем для решения этой проблемы. Единственный реальный способ получить это - восстановить временную метку последнего git коммита, который изменил определенный файл. Я заметил это довольно давно go и немного погуглил дал мне несколько ответов по SO, вот один из них, я думаю: Восстановите время модификации файла в Git
Я немного изменил его, чтобы соответствовать моим потребностям, и вот что я в итоге получил:
git ls-tree -r --name-only HEAD | while read filename; do
TS="$(git log -1 --format="%ct" -- ${filename})"
touch "${filename}" -mt "$(date --date="@$TS" "+%Y%m%d%H%M.%S")"
done
Этот работник отлично подходит для меня на Ubuntu CI, но решает эту проблему в зависимости от операционной системы c Способ с bash - это не то, что я хотел сделать, когда мне нужно было настроить Azure CI. По этой причине я написал скрипт Haskell, который работает для всех версий GH C -8.2 и новее, не требуя каких-либо неосновных зависимостей. Я использую его для всех своих проектов, и я добавлю сюда его сок, но также предоставлю ссылку на постоянный гист :
main = do
args <- getArgs
let rev = case args of
[] -> "HEAD"
(x:_) -> x
fs <- readProcess "git" ["ls-tree", "-r", "-t", "--full-name", "--name-only", rev] ""
let iso8601 = iso8601DateFormat (Just "%H:%M:%S%z")
restoreFileModtime fp = do
modTimeStr <- readProcess "git" ["log", "--pretty=format:%cI", "-1", rev, "--", fp] ""
modTime <- parseTimeM True defaultTimeLocale iso8601 modTimeStr
setModificationTime fp modTime
putStrLn $ "[" ++ modTimeStr ++ "] " ++ fp
putStrLn "Restoring modification time for all these files:"
mapM_ restoreFileModtime $ lines fs
Как бы вы go об использовании его без особых накладных расходов. Хитрость заключается в том, чтобы:
- использовать
stack
сам для запуска сценария - использовать точно такой же распознаватель, что и для проекта.
Выше двух пунктов гарантирует, что никакие избыточные зависимости или версии gh c не будут установлены. В общем, нужны только две вещи: stack
и что-то вроде curl
или wget
, и он будет работать кроссплатформенно:
# Script for restoring source files modification time from commit to avoid recompilation.
curl -sSkL https://gist.githubusercontent.com/lehins/fd36a8cc8bf853173437b17f6b6426ad/raw/4702d0252731ad8b21317375e917124c590819ce/git-modtime.hs -o git-modtime.hs
# Restore mod time and setup ghc, if it wasn't restored from cache
stack script --resolver ${RESOLVER} git-modtime.hs --package base --package time --package directory --package process
Вот реальный проект, который использует этот подход, и вы можете просмотреть его, чтобы увидеть, как он работает: massiv-io
Редактировать @Simon Michael в комментариях упомянул, что он не может воспроизвести эту проблему локально. Причиной этого является то, что не все так же, как на локальном уровне. Довольно часто абсолютный путь отличается, например, возможно, другие вещи, о которых я не могу думать прямо сейчас. Эти вещи вместе с отметкой времени исходного файла вызывают перекомпиляцию исходных файлов.
Например, следуйте этим шагам, и вы обнаружите, что ваш проект будет перекомпилирован:
~/tmp$ git clone git@github.com:fpco/safe-decimal.git
~/tmp$ cd safe-decimal
~/tmp/safe-decimal$ stack build
safe-decimal> configure (lib)
[1 of 2] Compiling Main
...
Configuring safe-decimal-0.2.0.0...
safe-decimal> build (lib)
Preprocessing library for safe-decimal-0.2.0.0..
Building library for safe-decimal-0.2.0.0..
[1 of 3] Compiling Numeric.Decimal.BoundedArithmetic
[2 of 3] Compiling Numeric.Decimal.Internal
[3 of 3] Compiling Numeric.Decimal
...
~/tmp/safe-decimal$ cd ../
~/tmp$ mv safe-decimal safe-decimal-moved
~/tmp$ cd safe-decimal-moved/
~/tmp/safe-decimal-moved$ stack build
safe-decimal-0.2.0.0: unregistering (old configure information not found)
safe-decimal> configure (lib)
[1 of 2] Compiling Main
...
Вы будете Видно, что расположение проекта вызвало проект здания. Несмотря на то, что сам проект был перестроен, вы заметите, что ни один из исходных файлов не был перекомпилирован. Теперь, если вы объедините эту процедуру с touch
исходного файла, этот исходный файл будет перекомпилирован.
Подводя итог:
- Среда может привести к тому, что проект будет rebuild
- Содержимое исходного файла может привести к перекомпиляции исходного файла (и других, зависящих от него)
- Среда вместе с содержимым исходного файла или изменение метки времени может вызвать проект вместе с этот исходный файл для перекомпиляции