3

Shake使用方法と新しいルールの作成方法を理解しようとしています。backup演習として、ルールと呼ばれるものを実装することにしました。

アイデアは、ファイルが存在しない場合、またはファイルが古すぎる場合 (24 時間以上) にファイルを生成することです。長いコマンドをメイクファイルに保存して、必要に応じて実行するのが好きです。例は mysql バックアップです。唯一の問題は、バックアップが既に存在し、make何もしない場合です。これを解決するには、次のいずれかを実行できます

  • 新しいバックアップをやり直す前に、以前のバックアップを削除します。
  • バックアップ対象にするphony
  • 架空のforce依存関係を追加します。手動または cron で変更できます。

私が望むのは、バックアップが24時間以上経過している場合はバックアップをやり直すことです(これtouch forceはcronで実行できます)。とにかく、それはで遊ぶための単なる例Shakeです。私が欲しいのは次のようなものです:

expirable "my_backup" 24 \out -> do
    cmd "mysqldump" backup_parameter out

ドキュメントを読みましたが、これを行う方法やルールを定義する方法、および an とは何かがわかりませんAction。クラスをインスタンス化する必要があることは理解していますが、Rule何が何であるかわかりません。

明確化

バックアップを自動的に実行するのではなく、オンデマンドでのみ実行したいのですが、最大で 24 時間に 1 回です。

シナリオの例として、リモート マシンに実稼働データベースがあり、ローカル コピーがあり、時間のかかるレポートをローカルで実行しています。通常のワークフローは

  • 本番バックアップをダウンロード
  • それを使用してローカルデータベースを更新します
  • ローカル倉庫データベースに非正規化テーブルをいくつか作成する
  • レポートを生成します。

レポートは毎日実行するのではなく、必要なときだけ実行します。そのため、24 時間ごとにレポートを実行したくありません。タイミング ビットを除いてメイクファイルを使用するのは簡単です。それらは面倒ですが、シェイクがどのように機能するかを深く理解するための不自然な例です。

したがって、最初make reportにバックアップを実行すると、データベースがすべて実行され、レポートが生成されます。ここで、レポートを変更したいと思います (テスト中のため)。バックアップを再生成する必要はありません(ローカルデータベースを更新する必要もありません)(私たちは夕方であり、翌日まで本番環境で何も変更されていないことを知っています)

そして翌日、または翌月、レポートを再実行します。今回は、バックアップを再度実行する必要があり、その依存関係もすべて再実行する必要があります。

基本的に私が必要とするルールは代わりに

やり直しタイムスタンプ = タイムスタンプ < 古い

やり直しタイムスタンプ = タイムスタンプ < 古い || 現在 > タイムスタンプ + 24*36000

しかし、このルールをどこに置くべきかわかりません。

問題は、それをどのように書くかではなく、どこに置くかです(上にあります)。(説明するのが)簡単な場合は、ユーザー(getLine)に「このターゲットをやり直しますか(はい/いいえ)?」と尋ねるルールを作成できます。

後で、データベース (または特定のテーブル) の最終更新に応じたルールも必要になります。データベースから情報を取得する方法は知っていますが、Shake に統合する方法はわかりません。

私はaが何であるかと混乱するかもしれませんRule。ルールを作るということは、ターゲットをどのように作るか (つまり、よりレシピ的なものです)、または Shake のアクションであると私が考えるものです。どこにルールがあるかというと、どうやってリメイクするかではなく、リメイクするかしないかを決めるルールのことです。make では、選択の余地がないので (タイムスタンプです)、そのような概念はありません。

4

2 に答える 2

1

Shake での「ルールの記述」には 2 つの意味があり*>ます。2) 新しいタイプのルールを定義する。たとえば、*>自分のようなオペレーターを定義する。Shake のほとんどのユーザーは 1 を頻繁に実行し、2 を実行することはありません。あなたの質問は完全に 2 に関係しているように見えますが、これは確かに可能です (すべてのルールは Shake のコアの外側で記述されています)。

ビルドのチェック中に実行するものを定義するには、Development.Shake.Ruleモジュールを使用し、型 class のインスタンスを定義する必要がありますRuleapply1通常、ユーザーがルールをタイプセーフな方法で使用できるように、関数をシュガーアップする必要があります。単純なルール (たとえば、変更日を調べて、変更されているかどうかを確認する) を作成する場合は、それほど難しくありません。より複雑なルールを実行している場合 (たとえば、ファイルが 1 日経過していないことを確認するなど) は少しトリッキーですが、それでも可能です。何がどこに保存されるかを考えるには、より注意が必要です。「ファイルが数秒以上古い場合に再構築する」例を取り上げると、次のように定義できます。

module MaximumAgeRule(maximumAge, includeMaximumAge) where

import Data.Maybe
import Development.Shake.Rule
import Development.Shake.Classes
import Development.Shake
import System.Directory as IO
import Data.Time

newtype MaxAgeQ = MaxAgeQ (FilePath, Double)
    deriving (Show,Binary,NFData,Hashable,Typeable,Eq)

instance Rule MaxAgeQ Double where
    storedValue _ (MaxAgeQ (file, secs)) = do
        exists <- IO.doesFileExist file
        if not exists then return Nothing else do
            mtime <- getModificationTime file
            now <- getCurrentTime
            return $ Just $ fromRational (toRational $ diffUTCTime now mtime)
    equalValue _ (MaxAgeQ (_, t)) old new = if new < t then EqualCheap else NotEqual

-- | Define that the file must be no more than N seconds old
maximumAge :: FilePath -> Double -> Action ()
maximumAge file secs = do
    apply1 $ MaxAgeQ (file, secs) :: Action Double
    return ()

includeMaximumAge :: Rules ()
includeMaximumAge = do
    rule $ \q@(MaxAgeQ (_, secs)) -> Just $ do
        opts <- getShakeOptions
        liftIO $ fmap (fromMaybe $ secs + 1) $ storedValue opts q

次に、ルールを次のように使用できます。

import Development.Shake
import MaximumAgeRule

main = shakeArgs shakeOptions $ do
    includeMaximumAge
    want ["output.txt"]
    "output.txt" *> \out -> do
        maximumAge out (24*60*60)
        liftIO $ putStrLn "rerunning"
        copyFile' "input.txt" "output.txt"

これで、ファイルが変更されるたびにファイルinput.txtがコピーされます。output.txtさらに、output.txtが 1 日以上経過している場合は、新たにコピーされます。

カスタムルールを使用しているため、それを with で宣言する必要がありますincludeMaximumAge(これは醜いですが、避けられません)。maximumAge次に、生成時に を呼び出しoutput.txtて、ファイルoutput.txtが 1 日以内であることを伝えます。そうである場合、ルールが再実行されます。シンプルで再利用可能。

定義のしくみ定義は少し複雑ですが、多くの人がルールを定義するとは思わないので、ルール定義ごとに StackOverflow の質問をするのは理にかなっているようです :)。キーが値を生成するルールのキーと値を定義する必要があります。キーについては、ファイル名と許容される古い値を格納する新しいタイプを宣言します (キーの場合は常にそうする必要があります)。値には、ファイルの古さを保存します。このstoredValue関数は、ファイルを照会してキーから値を取得します。関数はequalValue値を見て、値がEqualCheap(再構築しない) かNotEqual(再構築する) かを判断します。通常equalValueold == newメインのテストとして行いますが、ここでは前回の値は気にしません (無視oldします)。MaxAgeQであり、それを値と比較します。

このmaximumAge関数はapply1、 への依存関係を追加するために呼び出すだけでMaxAgeQ、何を呼び出すかをincludeMaximumAge定義しapply1ます。

于 2014-07-24T16:20:33.453 に答える