Write out hardcoded string

7 views
Skip to first unread message

Joachim Breitner

unread,
Apr 23, 2016, 12:49:16 PM4/23/16
to shake-bui...@googlegroups.com
Hi,

I in my program, I have a hard-coded ByteString (actually embedded
using file-embed), and I want the build system to write it out to a
file if that file does not yet exist, or if the string has changed.

I came up with this, but it is quite a mouth full. Can it be simplifie
or improved?

newtype GetIndexHTMLFile = GetIndexHTMLFile ()
    deriving (Show,Typeable,Eq,Hashable,Binary,NFData)

shakeMain = do
    shakeArgs shakeOptions $ do

    [..]

    getIndexHTMLFile <- addOracle $ \(GetIndexHTMLFile _) -> do
        return indexHtmlFile
    "site/index.html" *> \out -> do
        getIndexHTMLFile (GetIndexHTMLFile ()) >>= liftIO . (BS.writeFile out)
    want ["site/index.html"]

Greetings,
Joachim

--
Joachim “nomeata” Breitner
  ma...@joachim-breitner.dehttps://www.joachim-breitner.de/
  XMPP: nom...@joachim-breitner.de • OpenPGP-Key: 0xF0FBF51F
  Debian Developer: nom...@debian.org

signature.asc

Neil Mitchell

unread,
Apr 23, 2016, 4:18:46 PM4/23/16
to Joachim Breitner, shake-bui...@googlegroups.com
Hi Joachim,

The solution you've gone for certainly should work, but I'd be tempted
to go with the somewhat simpler:

writeFileChangedBS :: FilePath -> BS.ByteString -> Action ()
writeFileChangedBS name x = liftIO $ do
b <- doesFileExist name
if not b then BS.writeFile name x else do
b <- withFile name ReadMode $ \h -> do
src <- BS.hGetContents h
return $! src /= x
when b $ BS.writeFile name x

Then mark the rule for "site/index.html" as alwaysRerun and invoke
writeFileChangedBS. The code should be a bit simpler and reusable, and
you can skip storing the data in the Shake database as well as in the
binary and in the file.

The only downside is you have to read the file, which is another file
handle to open, but that shouldn't be terrible.

Another alternative, which might be the best performance wise, is to
have the Oracle store the hash of the bytestring, then you depend on
the oracle but use the bytestring directly. If the hash changes it
will rewrite, but the serialisation cost to the Shake database will be
minimal.

Thanks, Neil

Joachim Breitner

unread,
Apr 23, 2016, 5:03:47 PM4/23/16
to shake-bui...@googlegroups.com
Hi,

Am Samstag, den 23.04.2016, 21:18 +0100 schrieb Neil Mitchell:
> The solution you've gone for certainly should work, but I'd be
> tempted
> to go with the somewhat simpler:
>
> writeFileChangedBS :: FilePath -> BS.ByteString -> Action ()
> writeFileChangedBS name x = liftIO $ do
>     b <- doesFileExist name
>     if not b then BS.writeFile name x else do
>         b <- withFile name ReadMode $ \h -> do
>             src <- BS.hGetContents h
>             return $! src /= x
>         when b $ BS.writeFile name x
>
> Then mark the rule for "site/index.html" as alwaysRerun and invoke
> writeFileChangedBS. The code should be a bit simpler and reusable, and
> you can skip storing the data in the Shake database as well as in the
> binary and in the file.
>
> The only downside is you have to read the file, which is another file
> handle to open, but that shouldn't be terrible.

For some possibly non-rational reason, I wanted to avoid reading and
comparing the file on every invocation. But I guess by making it an
oracle, it just means that there is a copy in the shake data base, and
shake will read and compare it on every invocation.

There is a user-visible difference, though: Will manual changes to the
file prevail until the next invocation, or until the string in the
binary changes.

> Another alternative, which might be the best performance wise, is to
> have the Oracle store the hash of the bytestring, then you depend on
> the oracle but use the bytestring directly. If the hash changes it
> will rewrite, but the serialisation cost to the Shake database will
> be minimal.

Yes, that would be most elegant, I think.
signature.asc

Neil Mitchell

unread,
Apr 23, 2016, 5:15:37 PM4/23/16
to Joachim Breitner, shake-bui...@googlegroups.com
In all cases modifying the generated file will cause the action to rerun. In Shake the state of the output is a dependency of the rule. 

Thanks, Neil 

Joachim Breitner

unread,
Apr 23, 2016, 5:17:04 PM4/23/16
to shake-bui...@googlegroups.com
Hi,

Am Samstag, den 23.04.2016, 22:15 +0100 schrieb Neil Mitchell:
> In all cases modifying the generated file will cause the action to
> rerun. In Shake the state of the output is a dependency of the rule. 

indeed! I did not know that yet :-)
signature.asc
Reply all
Reply to author
Forward
0 new messages