packages feed

hackage-whatsnew (empty) → 0.1.0.0

raw patch · 5 files changed

+244/−0 lines, 5 filesdep +Cabaldep +basedep +containerssetup-changed

Dependencies added: Cabal, base, containers, directory, filepath, hackage-db, process, temporary

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Jeremy Shaw++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Jeremy Shaw nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER 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.
+ Main.hs view
@@ -0,0 +1,117 @@+module Main where++import qualified Data.Map as Map+import Distribution.Hackage.DB.Parsed+import Distribution.Package (PackageName(..), PackageIdentifier(PackageIdentifier, pkgName, pkgVersion))+import Distribution.PackageDescription (GenericPackageDescription(packageDescription), PackageDescription(package))+import Distribution.PackageDescription.Parse (readPackageDescription)+import Distribution.Simple.Utils (defaultPackageDesc)+-- import Distribution.Version (Version)+import Distribution.Text (display)+import Distribution.Verbosity (Verbosity, normal)+import System.Directory ( getAppUserDataDirectory )+import System.Exit (ExitCode(..), exitSuccess, exitWith)+import System.FilePath ( (</>), (<.>) )+import System.IO (hPutStr, hPutStrLn, stderr)+import System.IO.Temp (withSystemTempDirectory)+import System.Process++-- | get the package description for the local directory+local :: Verbosity -> IO PackageDescription+local v =+  fmap packageDescription (readPackageDescription v =<< defaultPackageDesc v)++-- | get the package description from hackage+--+-- This gets the latest version available.+hackage :: PackageName -- ^ the package name+        -> IO (Maybe PackageDescription)+hackage (PackageName pn) = do+  hackage <- readHackage+  case Map.lookup pn hackage of+    Nothing ->+      return Nothing+    (Just gpdMap) ->+      return $ Just $ packageDescription (snd $ head $ Map.toDescList gpdMap)++-- | calculate the directory to the tarball for `PackageIndentifier`+packageDir :: FilePath -> PackageIdentifier -> FilePath+packageDir repoLocal (PackageIdentifier pn version) =+    repoLocal </> display pn </> display version++-- | calculate the path to the tarball for `PackageIndentifier`+packageFile :: FilePath -> PackageIdentifier -> FilePath+packageFile repoLocal pi =+    (packageDir repoLocal pi) </> display pi <.> "tar.gz"++-- | fetch `PackageIdentifier` from hackage+--+-- returns path to downloaded `.tar.gz`+fetchFromHackage :: PackageIdentifier+                 -> IO FilePath+fetchFromHackage pi@(PackageIdentifier (PackageName pn) version) = do+  (ec, out, err) <- readProcessWithExitCode "cabal" ["fetch", "--no-dependencies", display pi] ""+  case ec of+    ExitSuccess -> do+      dd <- getAppUserDataDirectory "cabal"+      let repoLocal = dd </> "packages" </> "hackage.haskell.org" -- FIXME: this is the default, but users could be using a mirror or alternative repo+      return $ packageFile repoLocal pi+    (ExitFailure _) -> do+      putStrLn "Failed to fetch package from hackage."+      putStr out+      hPutStr stderr err+      exitWith (ExitFailure 2)++-- | create a `.tar.gz` in the local directory by calling `cabal sdist`.+cabalSDist :: PackageIdentifier -> IO FilePath+cabalSDist pi = do+  (ec, out, err) <- readProcessWithExitCode "cabal" ["sdist"] ""+  case ec of+    ExitFailure _ -> do+      putStr out+      hPutStr stderr err+      exitWith (ExitFailure 2)+    ExitSuccess ->+      return $ "dist" </> display pi <.> "tar.gz"++-- | calculate the `sha256sum`++sha256Sum :: FilePath -> IO String+sha256Sum fp =+    do sum <- readProcess "sha256sum" [fp] "" -- `catch`+       return $ takeWhile (/= ' ') sum++-- | extract two `tar.gz` filesa nd run a recursive diff on them.+tardiff :: FilePath -- ^ tarball 'a'+        -> FilePath -- ^ tarball 'b'+        -> IO ()+tardiff tar1 tar2 =+  withSystemTempDirectory "tardiff-XXXXXX" $ \tar1dir ->+  withSystemTempDirectory "tardiff-XXXXXX" $ \tar2dir -> do+    callProcess "tar" ["-C",tar1dir, "-x", "-z", "--strip=1", "-f", tar1]+    callProcess "tar" ["-C",tar2dir, "-x", "-z", "--strip=1", "-f", tar2]+    (ec, out, err) <- readProcessWithExitCode "diff" ["-r","-N","-u", tar1dir, tar2dir] ""+    case ec of+      ExitSuccess -> exitSuccess+      ExitFailure _ -> do+        putStr out+        hPutStr stderr err+        exitWith (ExitFailure 1)++-- | tie all the bits together+main :: IO ()+main = do+  let v = normal+  localPackage <- local v+  mHackagePackage <- hackage (pkgName $ package $ localPackage)+  case mHackagePackage of+    Nothing ->+        do hPutStrLn stderr $ "Could not find " ++ (unPackageName $ pkgName $ package $ localPackage) ++  " on hackage."+           exitWith (ExitFailure 2)+    (Just hackagePackage) -> do+      if (pkgVersion $ package localPackage) /= (pkgVersion $ package hackagePackage)+        then do hPutStrLn stderr $ "Versions do not match. Local = " ++ display (pkgVersion $ package $ localPackage) ++ ", Hackage = " ++ display (pkgVersion $ package $ hackagePackage)+        else return ()+      pf <- fetchFromHackage (package hackagePackage)+      lf <- cabalSDist (package localPackage)+      tardiff pf lf
+ README.md view
@@ -0,0 +1,64 @@+hackage-whatsnew [![Hackage](https://img.shields.io/hackage/v/hackage-whatsnew.svg)](https://hackage.haskell.org/package/hackage-whatsnew) [![Build Status](https://api.travis-ci.org/stepcut/hackage-whatsnew.svg?branch=master)](https://travis-ci.org/stepcut/hackage-whatsnew)+================++Do you often modify a package, check that it builds in travis, and then FORGET TO UPLOAD IT!++Then this tool is for you! Its raison d'etre is to see if you have+changes in your local directory which are not on hackage.++Usage+-----++`hackage-whatsnew` depends on the following executables:++ 1. cabal++ 2. tar++ 3. GNU diff (or any `diff` which supports the `-r`, `-u`, and `-N` options)++These binaries need to be in the current search path. Assuming+everything is installed, to use `hackage-whatsnew` you simply need to:++ 1. run `cabal update`++ 2. cd into the same directory as the `.cabal` file++ 3. run `hackage-whatsnew`++If no changes are detected, then nothing is printed and the exit code is 0.++If changes are detected a recursive diff is displayed and the exit code is 1.++How It Works+------------++This tool works as follows:++ 1. read the local `.cabal` file and figure out the package name++ 2. use `cabal fetch` to get the latest version of the package from hackage++ 3. use `cabal sdist` to generate the `.tar.gz` for the local working directory++ 4. untar both `.tar.gz` bundles into temporary directories++ 5. use `diff -ruN` to check for differences++ 6. exit with 0 if no differences found++ 7. exit with 1 if differences with found++ 8. exit with 2 if other errors encountered+++FAQ+---++**Q**: Why is it called `hackage-whatsnew` instead of `hackage-diff`?++**A**: Because `hackage-diff` was already taken. The `whatsnew` term is inspired by `darcs whatsnew`.++**Q**: Would it by great if the tool did XYZ?++**A**: Yes! Please submit a pull request.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hackage-whatsnew.cabal view
@@ -0,0 +1,31 @@+name:                hackage-whatsnew+version:             0.1.0.0+synopsis:            Check for differences between working directory and hackage+description:         This tool checks to see if the package in a local working directory+                     has changes which are not yet on hackage. This is useful to check if+                     you have forgetton to upload your changes to hackage.+license:             BSD3+license-file:        LICENSE+author:              Jeremy Shaw+maintainer:          jeremy@n-heptane.com+category:            Distribution+build-type:          Simple+cabal-version:       >=1.10+tested-with:         GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3+extra-source-files:  README.md++source-repository head+    type:     git+    location: https://github.com/stepcut/hackage-whatsnew.git++executable hackage-whatsnew+  main-is:             Main.hs+  build-depends:       base >=4.6 && <4.9,+                       Cabal >= 1.16 && < 1.23,+                       containers >=0.5 && <0.6,+                       directory >= 1.2 && < 1.3,+                       filepath >= 1.4 && < 1.5,+                       hackage-db >= 1.22 && < 1.23,+                       process >= 1.2 && < 1.5,+                       temporary >= 1.2 && < 1.3+  default-language:    Haskell2010