hackage2twitter (empty) → 0.2.1
raw patch · 4 files changed
+147/−0 lines, 4 filesdep +basedep +feeddep +feed2twittersetup-changed
Dependencies added: base, feed, feed2twitter
Files
- LICENSE +27/−0
- Setup.lhs +4/−0
- hackage2twitter.cabal +33/−0
- src/Main.hs +83/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2009, Tom Lokhorst++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ hackage2twitter.cabal view
@@ -0,0 +1,33 @@+name: hackage2twitter+version: 0.2.1+synopsis: Send new Hackage releases to Twitter+description: Build on the `feed2twitter` library, this program reads+ the Hackage RSS feed and tweets each new release to+ Twitter.+ .+ The Hackage feed is read only once. To keep updating, call+ this program every few minutes in a cron job.+ .+ A local cache of the last 20 tweets is kept in a file to+ make sure no duplicates are sent.+ .+ Usage:+ .+ > $ hackage2twitter username password cache-file [--debug-mode]+license: BSD3+license-file: LICENSE+author: Tom Lokhorst+maintainer: Tom Lokhorst <tom@lokhorst.eu>+homepage: http://github.com/tomlokhorst/hackage2twitter+stability: Experimental+category: Distribution, Web+build-type: Simple+cabal-version: >= 1.6++executable hackage2twitter+ build-depends: base >= 4,+ feed >= 0.3.6,+ feed2twitter >= 0.2+ main-is: Main.hs+ hs-source-dirs: src+
+ src/Main.hs view
@@ -0,0 +1,83 @@+-------------------------------------------------------------------------------+-- |+-- Module : Main+-- Copyright : (c) 2009, Tom Lokhorst+-- License : BSD3+--+-- Maintainer : Tom Lokhorst <tom@lokhorst.eu>+-- Stability : Experimental+--+-- Main module for the `hackage2twitter` executable.+-- Contains `rssItem2Tweet` function to parse Hackage RSS items.+--+-------------------------------------------------------------------------------+module Main where++import Text.RSS.Syntax+import Web.Feed2Twitter++import Data.Maybe+import Data.List+import System.Console.GetOpt+import System.Environment++main :: IO ()+main = do+ args <- getArgs+ (cfg, rest) <- processArgs defaultConfig options header args+ if length rest /= 3+ then putStrLn $ usageInfo header options+ else do+ let cfg' = cfg { username = rest !! 0+ , password = rest !! 1+ , cacheFile = rest !! 2+ }+ rss2twitter cfg' rssItem2tweet+ where+ header = "Usage: hackage2twitter USERNAME PASSWORD CACHE-FILE [OPTIONS...]"+ ++ ", with the following options:"++-- Map a RSS item to a tweet.+-- This function will fail on a few `fromJust`s if the Hackage RSS feed ever changes.+rssItem2tweet :: RSSItem -> Tweet+rssItem2tweet ri = trunc4url (title ++ ", added by " ++ uploader+ ++ maybe "." (": " ++) blurb) ++ url+ where+ title = filter (/='\n') . fromJust . rssItemTitle $ ri+ uploader = take (fromJust $ elemIndex ',' uploader') uploader'+ blurb = fmap (\x -> drop (x + 3) desc) (findSubList "<p>" desc)+ url = fromJust . rssItemLink $ ri+ guid = rssGuidValue . fromJust . rssItemGuid $ ri+ desc = map (\x -> if x == '\n' then ' ' else x)+ . fromJust . rssItemDescription $ ri+ uploader' = drop 12 desc++findSubList :: Eq a => [a] -> [a] -> Maybe Int+findSubList [] s2 = Nothing+findSubList s1 s2 = listToMaybe $ filter (\x -> isPrefixOf s1 $ drop x s2) xs+ where+ xs = elemIndices (head s1) s2++defaultConfig :: Config+defaultConfig = Config+ { feedUrl = "http://hackage.haskell.org/packages/archive/recent.rss"+ , username = ""+ , password = ""+ , cacheFile = ""+ , cacheSize = 20+ , debugMode = False+ }++options :: [OptDescr (Config -> Config)]+options =+ [ Option ['d'] ["debug-mode"] (NoArg (\c -> c { debugMode = True })) "Debug mode, send tweets to stdout."+ -- , Option ['V'] ["version"] (NoArg (\c -> c { showVersion = True })) "Show program version."+ ]++-- Seems like this function should already exist somewhere in a package.+processArgs :: a -> [OptDescr (a -> a)] -> String -> [String] -> IO (a, [String])+processArgs defaultConfig options header args =+ case getOpt Permute options args of+ (oargs, nonopts, [] ) -> return (foldl (flip ($)) defaultConfig oargs, nonopts)+ (_ , _ , errors) -> ioError $ userError $ (concat errors) ++ usageInfo header options+