2

私は現在、ビルド システムを make から Shake に移植するテストを行っており、障害にぶつかっています。

次のプロジェクト構造があるとします。

static/a.js
static/b.coffee

build/a.js
build/b.js

つまり、さまざまな入力拡張子が同一の出力拡張子にマップされるため、単純な"build//*.js" %>ルールは機能しません。

可能な限り優先順位の使用を避けたかったので、可能な入力のいずれかの存在をチェックするアドホック ビルド ルールを作成するのは面倒だと感じたため (特に、この状況は他のファイル タイプでも発生するため)、次のように作成しました。

data StaticFileMapping a = StaticFileMapping String String (FilePath -> FilePath -> Action a)

staticInputs :: FilePath -> StaticFileMapping a -> Action [FilePath]
staticInputs dir (StaticFileMapping iExt _ _) = (findFiles (dir </> "static") [iExt])

staticInputToOutput :: StaticFileMapping a -> FilePath -> FilePath
staticInputToOutput (StaticFileMapping _ oExt _) = (remapDir ["build"]) . (-<.> oExt)

staticTargets :: FilePath -> StaticFileMapping a -> Action [FilePath]
staticTargets dir sfm = (map $ staticInputToOutput sfm) <$> staticInputs dir sfm

rules :: FilePath -> StaticFileMapping a -> Rules ()
rules dir sfm@(StaticFileMapping _ _ process) = join $ mconcat . (map buildInputRule) <$> staticInputs dir sfm
    where buildInputRule :: FilePath -> Rules ()
          buildInputRule input = (staticInputToOutput sfm input) %> (process input)

.coffee -> .jsそうすれば、各入力タイプ ( 、 ) などのマッピングを定義でき、.svg -> .pngそれぞれの変換を実装するコードはほんのわずかです。そして、それはほとんど機能します。

しかし、私が知る限り、最初に値を捨てずにそこ(Action a)から先に進むことは不可能に思えます。Rules _Action

(Action a) -> (a -> Rules ()) -> Rules ()タイプまたはの関数はあり(Action a) -> (Rules a)ますか? どちらかを自分で実装できますか、それともライブラリのコードを変更する必要がありますか?

それとも、このアプローチ全体が頭がおかしいので、別のルートを取る必要がありますか?

4

1 に答える 1

3

まず、priority静的にルールを選択して実行するため、 using は機能しません。バックトラックしません。Shake が(提案した 2 つの関数に従って)Action生成する操作を実行しないことも重要です。これは、それ自体が定義する、または別のアクション ルールによって定義される を呼び出す可能性があるため、これらの呼び出しの順序を可視化するためです。あなたが考えているもの(ディレクトリリスト)には十分かもしれませんが、それは現在公開されていません(正確にそれを行う内部関数があります)。RulesActionneedRuleActionIO (Rules ()) -> Rules ()

アプローチの例をいくつか挙げると、.js/.coffeeファイルを変換するためのもっともらしいコマンドを定義すると便利です。

cmdCoffee :: FilePath -> FilePath -> Action ()
cmdCoffee src out = do
    need [src]
    cmd "coffee-script-convertor" [src] [out]

cmdJavascript :: FilePath -> FilePath -> Action ()
cmdJavascript = copyFile'

アプローチ 1: 使用するdoesFileExist

これは私の標準的なアプローチであり、次のように記述します。

"build/*.js" %> \out -> do
    let srcJs = "static" </> dropDirectory1 out
    let srcCf = srcJs -<.> "coffee"
    b <- doesFileExist srcCf
    if b then cmdCoffee srcCf out else cmdJavascript srcJs out

これにより、ユーザーがディレクトリにファイルを追加した場合.coffeeにルールを再実行する必要があるという依存関係が正確にキャプチャされます。doesFileExistこれがあなたにとって一般的なパターンである場合は、砂糖を増やすことを想像できます. StaticFileMapping構造のリストからそれを駆動することもできます(フィールドでagroupを実行して、それぞれを順番に呼び出すよりも、ルールごとに 1 つのルールを追加します)。このアプローチの利点は、ディレクトリのリストを作成する必要がないことです。ただし、そのコストはごくわずかです。oExtoExtdoesFileExistsiExtshake build/out.js

アプローチ 2:呼び出すにファイルを一覧表示するshake

書く代わりにmain = shakeArgs ...

import System.Directory.Extra(listFilesRecursive) -- from the "extra" package

main = do
    files <- listFilesRecursive "static"
    shakeArgs shakeOptions $ do
        forM_ files $ \src -> case takeExtension src of
            ".js" -> do
                 let out = "build" </> takeDirectory1 src
                 want [out]
                 out %> \_ -> cmdJavascript src out
            -- rules for all other types you care about
            _ -> return ()

ここでは、IO で操作してファイルのリストを取得し、以前に取得した値を参照してルールを追加できます。を追加rulesIO :: IO (Rules ()) -> Rules ()すると、 内のファイルを一覧表示できますshakeArgs

アプローチ 3:ルールのファイルを一覧表示する

ディレクトリのリストに基づいて、ファイル名と出力の間のマッピングを定義できます。

buildJs :: Action (Map FilePath (Action ()))
buildJs = do
    js <- getDirectoryFiles "static" ["*.js"]
    cf <- getDirectoryFiles "static" ["*.coffee"]
    return $ Map.fromList $
        [("build" </> j, cmdJavascript ("static" </> j) ("build" </> j)) | j <- js] ++
        [("build" </> c, cmdCoffee ("static" </> c) ("")) | c <- cf]

次に、それを一連のルールに持ち上げます。

action $ do
    mpJs <- buildJs
    need $ Map.keys mpJs
"//*.js" %> \out -> do
    mpJs <- buildJs
    mpJs Map.! out

ただし、これはビルドするすべてのファイルのディレクトリ リストを再計算するため、それをキャッシュして、一度だけ計算されるようにする必要があります。

mpJs <- newCache $ \() -> buildJs
action $ do
    mpJs <- mpJs ()
    need $ Map.keys mpJs
"//*.js" %> \out -> do
    mpJs <- mpJs ()
    mpJs Map.! out

このソリューションはおそらく元のアプローチに最も近いものですが、最も複雑だと思います。

于 2015-04-26T11:43:52.487 に答える