openSUSE Commits
Threads by month
- ----- 2024 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
July 2019
- 2 participants
- 2045 discussions
Hello community,
here is the log from the commit of package python-certbot-dns-cloudxns for openSUSE:Factory checked in at 2019-07-29 17:27:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot-dns-cloudxns (Old)
and /work/SRC/openSUSE:Factory/.python-certbot-dns-cloudxns.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-certbot-dns-cloudxns"
Mon Jul 29 17:27:43 2019 rev:9 rq:718486 version:0.36.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-certbot-dns-cloudxns/python-certbot-dns-cloudxns.changes 2019-07-18 15:21:46.700129518 +0200
+++ /work/SRC/openSUSE:Factory/.python-certbot-dns-cloudxns.new.4126/python-certbot-dns-cloudxns.changes 2019-07-29 17:27:45.638271799 +0200
@@ -4 +4 @@
-- update to version 0.36.0
+- update to version 0.36.0 (bsc#1141928)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
1
0
Hello community,
here is the log from the commit of package python-certbot-dns-cloudflare for openSUSE:Factory checked in at 2019-07-29 17:27:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot-dns-cloudflare (Old)
and /work/SRC/openSUSE:Factory/.python-certbot-dns-cloudflare.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-certbot-dns-cloudflare"
Mon Jul 29 17:27:39 2019 rev:8 rq:718485 version:0.36.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-certbot-dns-cloudflare/python-certbot-dns-cloudflare.changes 2019-07-18 15:21:43.404130107 +0200
+++ /work/SRC/openSUSE:Factory/.python-certbot-dns-cloudflare.new.4126/python-certbot-dns-cloudflare.changes 2019-07-29 17:27:42.510272956 +0200
@@ -4 +4 @@
-- update to version 0.36.0
+- update to version 0.36.0 (bsc#1141928)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
1
0
Hello community,
here is the log from the commit of package python-certbot-apache for openSUSE:Factory checked in at 2019-07-29 17:27:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot-apache (Old)
and /work/SRC/openSUSE:Factory/.python-certbot-apache.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-certbot-apache"
Mon Jul 29 17:27:34 2019 rev:9 rq:718484 version:0.36.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-certbot-apache/python-certbot-apache.changes 2019-07-18 15:21:39.912130730 +0200
+++ /work/SRC/openSUSE:Factory/.python-certbot-apache.new.4126/python-certbot-apache.changes 2019-07-29 17:27:38.450274459 +0200
@@ -4 +4 @@
-- update to version 0.36.0
+- update to version 0.36.0 (bsc#1141928)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
1
0
Hello community,
here is the log from the commit of package python-acme for openSUSE:Factory checked in at 2019-07-29 17:27:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-acme (Old)
and /work/SRC/openSUSE:Factory/.python-acme.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-acme"
Mon Jul 29 17:27:32 2019 rev:33 rq:718483 version:0.36.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-acme/python-acme.changes 2019-07-18 15:22:27.240122283 +0200
+++ /work/SRC/openSUSE:Factory/.python-acme.new.4126/python-acme.changes 2019-07-29 17:27:33.490276296 +0200
@@ -4 +4 @@
-- update to version 0.36.0
+- update to version 0.36.0 (bsc#1141928)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
1
0
Hello community,
here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2019-07-29 17:27:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
and /work/SRC/openSUSE:Factory/.crmsh.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh"
Mon Jul 29 17:27:27 2019 rev:160 rq:717840 version:4.1.0+git.1563261260.3b251242
Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2019-06-22 11:24:39.317415833 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new.4126/crmsh.changes 2019-07-29 17:27:29.426277800 +0200
@@ -1,0 +2,6 @@
+Tue Jul 16 07:19:00 UTC 2019 - kgronlund(a)suse.com
+
+- Update to version 4.1.0+git.1563261260.3b251242:
+ * doc: manpages: Fix spelling
+
+-------------------------------------------------------------------
Old:
----
crmsh-4.1.0+git.1561107542.79593cb0.tar.bz2
New:
----
crmsh-4.1.0+git.1563261260.3b251242.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.ft5bPn/_old 2019-07-29 17:27:30.046277570 +0200
+++ /var/tmp/diff_new_pack.ft5bPn/_new 2019-07-29 17:27:30.050277569 +0200
@@ -36,7 +36,7 @@
Summary: High Availability cluster command-line interface
License: GPL-2.0-or-later
Group: %{pkg_group}
-Version: 4.1.0+git.1561107542.79593cb0
+Version: 4.1.0+git.1563261260.3b251242
Release: 0
Url: http://crmsh.github.io
Source0: %{name}-%{version}.tar.bz2
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.ft5bPn/_old 2019-07-29 17:27:30.086277555 +0200
+++ /var/tmp/diff_new_pack.ft5bPn/_new 2019-07-29 17:27:30.086277555 +0200
@@ -1,4 +1,4 @@
<servicedata>
<service name="tar_scm">
<param name="url">git://github.com/ClusterLabs/crmsh.git</param>
- <param name="changesrevision">79593cb00d0e7ead6dc36bf1691deb5a47e354d3</param></service></servicedata>
\ No newline at end of file
+ <param name="changesrevision">d6fd16b91113c57af0e96b1d6aca0630ffdccaa1</param></service></servicedata>
\ No newline at end of file
++++++ crmsh-4.1.0+git.1561107542.79593cb0.tar.bz2 -> crmsh-4.1.0+git.1563261260.3b251242.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.1.0+git.1561107542.79593cb0/doc/crm.8.adoc new/crmsh-4.1.0+git.1563261260.3b251242/doc/crm.8.adoc
--- old/crmsh-4.1.0+git.1561107542.79593cb0/doc/crm.8.adoc 2019-06-21 10:59:02.000000000 +0200
+++ new/crmsh-4.1.0+git.1563261260.3b251242/doc/crm.8.adoc 2019-07-16 09:14:20.000000000 +0200
@@ -3405,7 +3405,7 @@
The `group` command creates a group of resources. This can be useful
when resources depend on other resources and require that those
-resources start in order on the same node. A commmon use of resource
+resources start in order on the same node. A common use of resource
groups is to ensure that a server and a virtual IP are located
together, and that the virtual IP is started before the server.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-1.2.adoc new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-1.2.adoc
--- old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-1.2.adoc 2019-06-21 10:59:02.000000000 +0200
+++ new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-1.2.adoc 2019-07-16 09:14:20.000000000 +0200
@@ -1747,7 +1747,7 @@
The `group` command creates a group of resources. This can be useful
when resources depend on other resources and require that those
-resources start in order on the same node. A commmon use of resource
+resources start in order on the same node. A common use of resource
groups is to ensure that a server and a virtual IP are located
together, and that the virtual IP is started before the server.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-2.0.adoc new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-2.0.adoc
--- old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-2.0.adoc 2019-06-21 10:59:02.000000000 +0200
+++ new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-2.0.adoc 2019-07-16 09:14:20.000000000 +0200
@@ -3053,7 +3053,7 @@
The `group` command creates a group of resources. This can be useful
when resources depend on other resources and require that those
-resources start in order on the same node. A commmon use of resource
+resources start in order on the same node. A common use of resource
groups is to ensure that a server and a virtual IP are located
together, and that the virtual IP is started before the server.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-3.adoc new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-3.adoc
--- old/crmsh-4.1.0+git.1561107542.79593cb0/doc/website-v1/man-3.adoc 2019-06-21 10:59:02.000000000 +0200
+++ new/crmsh-4.1.0+git.1563261260.3b251242/doc/website-v1/man-3.adoc 2019-07-16 09:14:20.000000000 +0200
@@ -3314,7 +3314,7 @@
The `group` command creates a group of resources. This can be useful
when resources depend on other resources and require that those
-resources start in order on the same node. A commmon use of resource
+resources start in order on the same node. A common use of resource
groups is to ensure that a server and a virtual IP are located
together, and that the virtual IP is started before the server.
1
0
Hello community,
here is the log from the commit of package stack for openSUSE:Factory checked in at 2019-07-29 17:27:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/stack (Old)
and /work/SRC/openSUSE:Factory/.stack.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "stack"
Mon Jul 29 17:27:16 2019 rev:22 rq:715424 version:2.1.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/stack/stack.changes 2019-06-19 21:13:30.422807903 +0200
+++ /work/SRC/openSUSE:Factory/.stack.new.4126/stack.changes 2019-07-29 17:27:26.506278881 +0200
@@ -1,0 +2,60 @@
+Sun Jul 14 02:01:50 UTC 2019 - psimons(a)suse.com
+
+- Update stack to version 2.1.3.
+
+ Behavior changes:
+
+ * Disable WAL mode for SQLite3 databases, to improve compatibility with
+ some platforms and filesystems. See
+ [#4876](https://github.com/commercialhaskell/stack/issues/4876).
+
+ * By default, do not perform expiry checks in Hackage Security. See
+ [#4928](https://github.com/commercialhaskell/stack/issues/4928).
+
+ Other enhancements:
+
+ * Do not rerun expected test failures. This is mostly a change that
+ will only affect the Stackage Curator use case, but there is now an
+ additional message letting the user know when a previously-failed
+ test case is being rerun.
+
+ * Move configure information for local packages back to .stack-work to
+ improve caching. See
+ [#4893](https://github.com/commercialhaskell/stack/issues/4893).
+
+ Bug fixes:
+
+ * Fix to allow dependencies on specific versions of local git repositories. See
+ [#4862](https://github.com/commercialhaskell/stack/pull/4862)
+
+ * Allow Stack commands to be run in Nix mode without having a project file
+ available. See
+ [#4854](https://github.com/commercialhaskell/stack/issues/4864).
+
+ * Removes dependency on gnu-tar for OSX and Linux environment. The
+ `--force-local` option was required only for windows environment.
+
+ * Properly wait for the `tar` subprocess to complete before returning, thereby
+ avoiding a SIGTERM screwing up GHC installation. See
+ [#4888](https://github.com/commercialhaskell/stack/issues/4888).
+
+ * Use package complete locations from lock files when resolving dependencies
+ in `extra-deps`. See
+ [#4887](https://github.com/commercialhaskell/stack/issues/4887).
+
+ * Set the `HASKELL_DIST_DIR` environment to a proper package dist
+ directory so `doctest` is able to load modules autogenerated by Cabal.
+
+ * Expose package library when running tests.
+
+ * Fix support for non-ASCII module names. See
+ [4938](https://github.com/commercialhaskell/stack/issues/4938)
+
+ Other changes:
+
+ * Rename `pantry-tmp` package back to `pantry`, now that we have gained
+ maintainership (which had been used by someone else for a candidate-only test
+ that made it look like the name was free but prevented uploading a real
+ package).
+
+-------------------------------------------------------------------
Old:
----
stack-2.1.1.1.tar.gz
stack.cabal
New:
----
stack-2.1.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ stack.spec ++++++
--- /var/tmp/diff_new_pack.5b2jAT/_old 2019-07-29 17:27:28.034278315 +0200
+++ /var/tmp/diff_new_pack.5b2jAT/_new 2019-07-29 17:27:28.038278314 +0200
@@ -19,14 +19,13 @@
%global pkg_name stack
%bcond_with tests
Name: %{pkg_name}
-Version: 2.1.1.1
+Version: 2.1.3
Release: 0
Summary: The Haskell Tool Stack
License: BSD-3-Clause
Group: Development/Libraries/Haskell
URL: https://hackage.haskell.org/package/%{name}
Source0: https://hackage.haskell.org/package/%{name}-%{version}/%{name}-%{version}.t…
-Source1: https://hackage.haskell.org/package/%{name}-%{version}/revision/1.cabal#/%{…
Patch01: enable-undecidable-instances-extension.patch
BuildRequires: chrpath
BuildRequires: ghc-Cabal-devel
@@ -74,7 +73,7 @@
BuildRequires: ghc-network-uri-devel
BuildRequires: ghc-open-browser-devel
BuildRequires: ghc-optparse-applicative-devel
-BuildRequires: ghc-pantry-tmp-devel
+BuildRequires: ghc-pantry-devel
BuildRequires: ghc-path-devel
BuildRequires: ghc-path-io-devel
BuildRequires: ghc-persistent-devel
@@ -162,7 +161,6 @@
%prep
%setup -q
%patch01 -p1
-cp -p %{SOURCE1} %{name}.cabal-broken
%build
%define cabal_configure_options -fdisable-git-info -fhide-dependency-versions -fsupported-build
++++++ enable-undecidable-instances-extension.patch ++++++
--- /var/tmp/diff_new_pack.5b2jAT/_old 2019-07-29 17:27:28.058278306 +0200
+++ /var/tmp/diff_new_pack.5b2jAT/_new 2019-07-29 17:27:28.058278306 +0200
@@ -1,7 +1,16 @@
-Index: stack-2.1.1.1/src/Stack/Storage.hs
+Index: stack-2.1.3/src/Stack/Storage/User.hs
===================================================================
---- stack-2.1.1.1.orig/src/Stack/Storage.hs 2019-06-18 17:43:10.714699851 +0000
-+++ stack-2.1.1.1/src/Stack/Storage.hs 2019-06-18 17:43:23.411761299 +0000
+--- stack-2.1.3.orig/src/Stack/Storage/User.hs 2019-07-11 16:55:25.000000000 +0000
++++ stack-2.1.3/src/Stack/Storage/User.hs 2019-07-14 19:52:04.771135933 +0000
+@@ -1,3 +1,4 @@
++{-# LANGUAGE UndecidableInstances #-}
+ {-# LANGUAGE FlexibleInstances #-}
+ {-# LANGUAGE GADTs #-}
+ {-# LANGUAGE GeneralizedNewtypeDeriving #-}
+Index: stack-2.1.3/src/Stack/Storage/Project.hs
+===================================================================
+--- stack-2.1.3.orig/src/Stack/Storage/Project.hs 2019-07-11 16:55:25.000000000 +0000
++++ stack-2.1.3/src/Stack/Storage/Project.hs 2019-07-14 19:53:10.803419216 +0000
@@ -1,3 +1,4 @@
+{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
++++++ stack-2.1.1.1.tar.gz -> stack-2.1.3.tar.gz ++++++
++++ 3364 lines of diff (skipped)
1
0
Hello community,
here is the log from the commit of package ghc-unliftio for openSUSE:Factory checked in at 2019-07-29 17:27:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-unliftio (Old)
and /work/SRC/openSUSE:Factory/.ghc-unliftio.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-unliftio"
Mon Jul 29 17:27:10 2019 rev:8 rq:715423 version:0.2.12
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-unliftio/ghc-unliftio.changes 2019-06-12 13:18:58.240560658 +0200
+++ /work/SRC/openSUSE:Factory/.ghc-unliftio.new.4126/ghc-unliftio.changes 2019-07-29 17:27:15.726282871 +0200
@@ -1,0 +2,18 @@
+Sat Jul 13 02:01:41 UTC 2019 - psimons(a)suse.com
+
+- Update unliftio to version 0.2.12.
+ ## 0.2.12
+
+ * Dropped support for ghc-7.8
+ * Addition of `UnliftIO.IO.File` module and atomic+durable file writes:
+
+ * `writeBinaryFile`
+ * `writeBinaryFileAtomic`
+ * `writeBinaryFileDurable`
+ * `writeBinaryFileDurableAtomic`
+ * `withBinaryFileAtomic`
+ * `withBinaryFileDurable`
+ * `withBinaryFileDurableAtomic`
+ * `ensureFileDurable`
+
+-------------------------------------------------------------------
Old:
----
unliftio-0.2.11.tar.gz
New:
----
unliftio-0.2.12.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-unliftio.spec ++++++
--- /var/tmp/diff_new_pack.bUWrLF/_old 2019-07-29 17:27:18.554281825 +0200
+++ /var/tmp/diff_new_pack.bUWrLF/_new 2019-07-29 17:27:18.582281814 +0200
@@ -19,7 +19,7 @@
%global pkg_name unliftio
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.2.11
+Version: 0.2.12
Release: 0
Summary: The MonadUnliftIO typeclass for unlifting monads to IO (batteries included)
License: MIT
@@ -28,6 +28,7 @@
Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{ve…
BuildRequires: ghc-Cabal-devel
BuildRequires: ghc-async-devel
+BuildRequires: ghc-bytestring-devel
BuildRequires: ghc-deepseq-devel
BuildRequires: ghc-directory-devel
BuildRequires: ghc-filepath-devel
++++++ unliftio-0.2.11.tar.gz -> unliftio-0.2.12.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/ChangeLog.md new/unliftio-0.2.12/ChangeLog.md
--- old/unliftio-0.2.11/ChangeLog.md 2019-06-07 12:37:42.000000000 +0200
+++ new/unliftio-0.2.12/ChangeLog.md 2019-07-12 06:21:01.000000000 +0200
@@ -1,5 +1,19 @@
# Changelog for unliftio
+## 0.2.12
+
+* Dropped support for ghc-7.8
+* Addition of `UnliftIO.IO.File` module and atomic+durable file writes:
+
+ * `writeBinaryFile`
+ * `writeBinaryFileAtomic`
+ * `writeBinaryFileDurable`
+ * `writeBinaryFileDurableAtomic`
+ * `withBinaryFileAtomic`
+ * `withBinaryFileDurable`
+ * `withBinaryFileDurableAtomic`
+ * `ensureFileDurable`
+
## 0.2.11
* Deprecate `forkWithUnmask` in favor of the newly added `forkIOWithUnmask` to
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/cbits/file-posix.c new/unliftio-0.2.12/cbits/file-posix.c
--- old/unliftio-0.2.11/cbits/file-posix.c 1970-01-01 01:00:00.000000000 +0100
+++ new/unliftio-0.2.12/cbits/file-posix.c 2019-07-12 06:21:01.000000000 +0200
@@ -0,0 +1,34 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+int unliftio_o_tmpfile( void )
+{
+#ifdef __O_TMPFILE
+ return __O_TMPFILE;
+#else
+ return 0;
+#endif
+}
+
+int unliftio_at_fdcwd( void )
+{
+ return AT_FDCWD;
+}
+
+int unliftio_at_symlink_follow( void )
+{
+ return AT_SYMLINK_FOLLOW;
+}
+
+
+int unliftio_s_irusr( void )
+{
+ return S_IRUSR;
+}
+
+int unliftio_s_iwusr( void )
+{
+ return S_IWUSR;
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/src/UnliftIO/IO/File/Posix.hs new/unliftio-0.2.12/src/UnliftIO/IO/File/Posix.hs
--- old/unliftio-0.2.11/src/UnliftIO/IO/File/Posix.hs 1970-01-01 01:00:00.000000000 +0100
+++ new/unliftio-0.2.12/src/UnliftIO/IO/File/Posix.hs 2019-07-12 06:21:01.000000000 +0200
@@ -0,0 +1,582 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
+module UnliftIO.IO.File.Posix
+ ( withBinaryFileDurable
+ , withBinaryFileDurableAtomic
+ , withBinaryFileAtomic
+ , ensureFileDurable
+ )
+ where
+
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative
+#endif
+import Control.Monad (forM_, guard, unless, void, when)
+import Control.Monad.IO.Unlift
+import Data.Bits (Bits, (.|.))
+import Data.ByteString (ByteString)
+import Data.Maybe (fromMaybe)
+import Data.Typeable (cast)
+import Foreign (allocaBytes)
+import Foreign.C (CInt(..), throwErrnoIfMinus1, throwErrnoIfMinus1Retry,
+ throwErrnoIfMinus1Retry_)
+import GHC.IO.Device (IODeviceType(RegularFile))
+import qualified GHC.IO.Device as Device
+import GHC.IO.Exception (IOErrorType(UnsupportedOperation))
+import qualified GHC.IO.FD as FD
+import qualified GHC.IO.Handle.FD as HandleFD
+import qualified GHC.IO.Handle.Types as HandleFD (Handle(..), Handle__(..))
+import System.Directory (removeFile)
+import System.FilePath (takeDirectory, takeFileName)
+import System.IO (Handle, IOMode(..), SeekMode(..), hGetBuf, hPutBuf,
+ openBinaryTempFile)
+import System.IO.Error (ioeGetErrorType, isAlreadyExistsError,
+ isDoesNotExistError)
+import qualified System.Posix.Files as Posix
+import System.Posix.Internals (CFilePath, c_close, c_safe_open, withFilePath)
+import System.Posix.Types (CMode(..), Fd(..), FileMode)
+import UnliftIO.Exception
+import UnliftIO.IO
+import UnliftIO.MVar
+
+-- NOTE: System.Posix.Internal doesn't re-export this constants so we have to
+-- recreate-them here
+
+newtype CFlag =
+ CFlag CInt
+ deriving (Eq, Show, Bits)
+
+foreign import ccall unsafe "HsBase.h __hscore_o_rdonly" o_RDONLY :: CFlag
+foreign import ccall unsafe "HsBase.h __hscore_o_wronly" o_WRONLY :: CFlag
+foreign import ccall unsafe "HsBase.h __hscore_o_rdwr" o_RDWR :: CFlag
+foreign import ccall unsafe "HsBase.h __hscore_o_append" o_APPEND :: CFlag
+foreign import ccall unsafe "HsBase.h __hscore_o_creat" o_CREAT :: CFlag
+foreign import ccall unsafe "HsBase.h __hscore_o_noctty" o_NOCTTY :: CFlag
+
+-- After here, we have our own imports
+
+-- On non-Linux operating systems that do not support `O_TMPFILE` the value of
+-- `o_TMPFILE` will be 0, which is then used to fallback onto a different
+-- implementation of temporary files.
+foreign import ccall unsafe "file-posix.c unliftio_o_tmpfile" o_TMPFILE :: CFlag
+
+
+-- | Whenever Operating System does not support @O_TMPFILE@ flag and anonymous
+-- temporary files then `o_TMPFILE` flag will be set to @0@
+o_TMPFILE_not_supported :: CFlag
+o_TMPFILE_not_supported = CFlag 0
+
+newtype CAt = CAt
+ { unCAt :: CInt
+ } deriving (Eq, Show, Bits)
+
+foreign import ccall unsafe "file-posix.c unliftio_at_fdcwd" at_FDCWD :: CAt
+foreign import ccall unsafe "file-posix.c unliftio_at_symlink_follow" at_SYMLINK_FOLLOW :: CAt
+foreign import ccall unsafe "file-posix.c unliftio_s_irusr" s_IRUSR :: CMode
+foreign import ccall unsafe "file-posix.c unliftio_s_iwusr" s_IWUSR :: CMode
+
+c_open :: CFilePath -> CFlag -> CMode -> IO CInt
+c_open fp (CFlag flags) = c_safe_open fp flags
+
+foreign import ccall safe "fcntl.h openat"
+ c_safe_openat :: CInt -> CFilePath -> CInt -> CMode -> IO CInt
+
+c_openat :: DirFd -> CFilePath -> CFlag -> CMode -> IO CInt
+c_openat (DirFd (Fd fd)) fp (CFlag flags) = c_safe_openat fd fp flags
+
+foreign import ccall safe "fcntl.h renameat"
+ c_safe_renameat :: CInt -> CFilePath -> CInt -> CFilePath -> IO CInt
+
+c_renameat :: DirFd -> CFilePath -> DirFd -> CFilePath -> IO CInt
+c_renameat (DirFd (Fd fdFrom)) cFpFrom (DirFd (Fd fdTo)) cFpTo =
+ c_safe_renameat fdFrom cFpFrom fdTo cFpTo
+
+foreign import ccall safe "unistd.h fsync"
+ c_safe_fsync :: CInt -> IO CInt
+
+c_fsync :: Fd -> IO CInt
+c_fsync (Fd fd) = c_safe_fsync fd
+
+foreign import ccall safe "unistd.h linkat"
+ c_safe_linkat :: CInt -> CFilePath -> CInt -> CFilePath -> CInt -> IO CInt
+
+c_linkat :: CAt -> CFilePath -> Either DirFd CAt -> CFilePath -> CAt -> IO CInt
+c_linkat cat oldPath eNewDir newPath (CAt flags) =
+ c_safe_linkat (unCAt cat) oldPath newDir newPath flags
+ where
+ unFd (Fd fd) = fd
+ newDir = either (unFd . unDirFd) unCAt eNewDir
+
+std_flags, output_flags, read_flags, write_flags, rw_flags,
+ append_flags :: CFlag
+std_flags = o_NOCTTY
+output_flags = std_flags .|. o_CREAT
+read_flags = std_flags .|. o_RDONLY
+write_flags = output_flags .|. o_WRONLY
+rw_flags = output_flags .|. o_RDWR
+append_flags = write_flags .|. o_APPEND
+
+ioModeToFlags :: IOMode -> CFlag
+ioModeToFlags iomode =
+ case iomode of
+ ReadMode -> read_flags
+ WriteMode -> write_flags
+ ReadWriteMode -> rw_flags
+ AppendMode -> append_flags
+
+newtype DirFd = DirFd
+ { unDirFd :: Fd
+ }
+
+-- | Returns a low-level file descriptor for a directory path. This function
+-- exists given the fact that 'openFile' does not work with directories.
+--
+-- If you use this function, make sure you are working on a masked state,
+-- otherwise async exceptions may leave file descriptors open.
+openDir :: MonadIO m => FilePath -> m Fd
+openDir fp
+ -- TODO: Investigate what is the situation with Windows FS in regards to non_blocking
+ -- NOTE: File operations _do not support_ non_blocking on various kernels, more
+ -- info can be found here: https://ghc.haskell.org/trac/ghc/ticket/15153
+ =
+ liftIO $
+ withFilePath fp $ \cFp ->
+ Fd <$>
+ throwErrnoIfMinus1Retry
+ "openDir"
+ (c_open cFp (ioModeToFlags ReadMode) 0o660)
+
+-- | Closes a 'Fd' that points to a Directory.
+closeDirectory :: MonadIO m => DirFd -> m ()
+closeDirectory (DirFd (Fd dirFd)) =
+ liftIO $
+ throwErrnoIfMinus1Retry_ "closeDirectory" $ c_close dirFd
+
+-- | Executes the low-level C function fsync on a C file descriptor
+fsyncFileDescriptor
+ :: MonadIO m
+ => String -- ^ Meta-description for error messages
+ -> Fd -- ^ C File Descriptor
+ -> m ()
+fsyncFileDescriptor name fd =
+ liftIO $ void $ throwErrnoIfMinus1 ("fsync - " ++ name) $ c_fsync fd
+
+-- | Call @fsync@ on the file handle. Accepts an arbitary string for error reporting.
+fsyncFileHandle :: String -> Handle -> IO ()
+fsyncFileHandle fname hdl = withHandleFd hdl (fsyncFileDescriptor (fname ++ "/File"))
+
+
+-- | Call @fsync@ on the opened directory file descriptor. Accepts an arbitary
+-- string for error reporting.
+fsyncDirectoryFd :: String -> DirFd -> IO ()
+fsyncDirectoryFd fname = fsyncFileDescriptor (fname ++ "/Directory") . unDirFd
+
+
+-- | Opens a file from a directory, using this function in favour of a regular
+-- 'openFile' guarantees that any file modifications are kept in the same
+-- directory where the file was opened. An edge case scenario is a mount
+-- happening in the directory where the file was opened while your program is
+-- running.
+--
+-- If you use this function, make sure you are working on an masked state,
+-- otherwise async exceptions may leave file descriptors open.
+--
+openFileFromDir :: MonadIO m => DirFd -> FilePath -> IOMode -> m Handle
+openFileFromDir dirFd filePath@(takeFileName -> fileName) iomode =
+ liftIO $
+ withFilePath fileName $ \cFileName ->
+ bracketOnError
+ (do fileFd <-
+ throwErrnoIfMinus1Retry "openFileFromDir" $
+ c_openat dirFd cFileName (ioModeToFlags iomode) 0o666
+ {- Can open directory with read only -}
+ FD.mkFD
+ fileFd
+ iomode
+ Nothing {- no stat -}
+ False {- not a socket -}
+ False {- non_blocking -}
+ `onException`
+ c_close fileFd)
+ (liftIO . Device.close . fst)
+ (\(fD, fd_type)
+ -- we want to truncate() if this is an open in WriteMode, but only if the
+ -- target is a RegularFile. ftruncate() fails on special files like
+ -- /dev/null.
+ -> do
+ when (iomode == WriteMode && fd_type == RegularFile) $
+ Device.setSize fD 0
+ HandleFD.mkHandleFromFD fD fd_type filePath iomode False Nothing)
+
+
+-- | Similar to `openFileFromDir`, but will open an anonymous (nameless)
+-- temporary file in the supplied directory
+openAnonymousTempFileFromDir ::
+ MonadIO m =>
+ Maybe DirFd
+ -- ^ If a file descriptor is given for the directory where the target file is/will be
+ -- located in, then it will be used for opening an anonymous file. Otherwise
+ -- anonymous will be opened unattached to any file path.
+ -> FilePath
+ -- ^ File path of the target file that we are working on.
+ -> IOMode
+ -> m Handle
+openAnonymousTempFileFromDir mDirFd filePath iomode =
+ liftIO $
+ case mDirFd of
+ Just dirFd -> withFilePath "." (openAnonymousWith . c_openat dirFd)
+ Nothing ->
+ withFilePath (takeDirectory filePath) (openAnonymousWith . c_open)
+ where
+ fdName = "openAnonymousTempFileFromDir - " ++ filePath
+ ioModeToTmpFlags :: IOMode -> CFlag
+ ioModeToTmpFlags =
+ \case
+ ReadMode -> o_RDWR -- It is an error to create a O_TMPFILE with O_RDONLY
+ ReadWriteMode -> o_RDWR
+ _ -> o_WRONLY
+ openAnonymousWith fopen =
+ bracketOnError
+ (do fileFd <-
+ throwErrnoIfMinus1Retry "openAnonymousTempFileFromDir" $
+ fopen (o_TMPFILE .|. ioModeToTmpFlags iomode) (s_IRUSR .|. s_IWUSR)
+ FD.mkFD
+ fileFd
+ iomode
+ Nothing {- no stat -}
+ False {- not a socket -}
+ False {- non_blocking -}
+ `onException`
+ c_close fileFd)
+ (liftIO . Device.close . fst)
+ (\(fD, fd_type) ->
+ HandleFD.mkHandleFromFD fD fd_type fdName iomode False Nothing)
+
+
+atomicDurableTempFileRename ::
+ DirFd -> Maybe FileMode -> Handle -> Maybe FilePath -> FilePath -> IO ()
+atomicDurableTempFileRename dirFd mFileMode tmpFileHandle mTmpFilePath filePath = do
+ fsyncFileHandle "atomicDurableTempFileCreate" tmpFileHandle
+ -- at this point we know that the content has been persisted to the storage it
+ -- is safe to do the atomic move/replace
+ let eTmpFile = maybe (Left tmpFileHandle) Right mTmpFilePath
+ atomicTempFileRename (Just dirFd) mFileMode eTmpFile filePath
+ -- Important to close the handle, so the we can fsync the directory
+ hClose tmpFileHandle
+ -- file path is updated, now we can fsync the directory
+ fsyncDirectoryFd "atomicDurableTempFileCreate" dirFd
+
+
+-- | There will be an attempt to atomically convert an invisible temporary file
+-- into a target file at the supplied file path. In case when there is already a
+-- file at that file path, a new visible temporary file will be created in the
+-- same folder and then atomically renamed into the target file path, replacing
+-- any existing file. This is necessary since `c_safe_linkat` cannot replace
+-- files atomically and we have to fall back onto `c_safe_renameat`. This should
+-- not be a problem in practice, since lifetime of such visible file is
+-- extremely short and it will be cleaned up regardless of the outcome of the
+-- rename.
+--
+-- It is important to note, that whenever a file descriptor for the containing
+-- directory is supplied, renaming and linking will be done in its context,
+-- thus allowing to do proper fsyncing if durability is necessary.
+--
+-- __NOTE__: this function will work only on Linux.
+--
+atomicTempFileCreate ::
+ Maybe DirFd
+ -- ^ Possible handle for the directory where the target file is located. Which
+ -- means that the file is already in that directory, just without a name. In other
+ -- words it was opened before with `openAnonymousTempFileFromDir`
+ -> Maybe FileMode
+ -- ^ If file permissions are supplied they will be set on the new file prior
+ -- to atomic rename.
+ -> Handle
+ -- ^ Handle to the anonymous temporary file created with `c_openat` and
+ -- `o_TMPFILE`
+ -> FilePath
+ -- ^ File path for the target file.
+ -> IO ()
+atomicTempFileCreate mDirFd mFileMode tmpFileHandle filePath =
+ withHandleFd tmpFileHandle $ \fd@(Fd cFd) ->
+ withFilePath ("/proc/self/fd/" ++ show cFd) $ \cFromFilePath ->
+ withFilePath filePathName $ \cToFilePath -> do
+ let fileMode = fromMaybe Posix.stdFileMode mFileMode
+ -- work around for the glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17523
+ Posix.setFdMode fd fileMode
+ let safeLink which to =
+ throwErrnoIfMinus1Retry_
+ ("atomicFileCreate - c_safe_linkat - " ++ which) $
+ -- see `man linkat` and `man openat` for more info
+ c_linkat at_FDCWD cFromFilePath cDirFd to at_SYMLINK_FOLLOW
+ eExc <-
+ tryJust (guard . isAlreadyExistsError) $
+ safeLink "anonymous" cToFilePath
+ case eExc of
+ Right () -> pure ()
+ Left () ->
+ withBinaryTempFileFor filePath $ \visTmpFileName visTmpFileHandle -> do
+ hClose visTmpFileHandle
+ removeFile visTmpFileName
+ case mDirFd of
+ Nothing -> do
+ withFilePath visTmpFileName (safeLink "visible")
+ Posix.rename visTmpFileName filePath
+ Just dirFd ->
+ withFilePath (takeFileName visTmpFileName) $ \cVisTmpFile -> do
+ safeLink "visible" cVisTmpFile
+ throwErrnoIfMinus1Retry_
+ "atomicFileCreate - c_safe_renameat" $
+ c_renameat dirFd cVisTmpFile dirFd cToFilePath
+ where
+ (cDirFd, filePathName) =
+ case mDirFd of
+ Nothing -> (Right at_FDCWD, filePath)
+ Just dirFd -> (Left dirFd, takeFileName filePath)
+
+atomicTempFileRename ::
+ Maybe DirFd
+ -- ^ Possible handle for the directory where the target file is located.
+ -> Maybe FileMode
+ -- ^ If file permissions are supplied they will be set on the new file prior
+ -- to atomic rename.
+ -> Either Handle FilePath
+ -- ^ Temporary file. If a handle is supplied, it means it was opened with
+ -- @O_TMPFILE@ flag and thus we are on the Linux OS and can safely call
+ -- `atomicTempFileCreate`
+ -> FilePath
+ -- ^ File path for the target file. Whenever `DirFd` is supplied, it must be
+ -- the containgin directory fo this file, but that invariant is not enforced
+ -- within this function.
+ -> IO ()
+atomicTempFileRename mDirFd mFileMode eTmpFile filePath =
+ case eTmpFile of
+ Left tmpFileHandle ->
+ atomicTempFileCreate mDirFd mFileMode tmpFileHandle filePath
+ Right tmpFilePath -> do
+ forM_ mFileMode $ \fileMode -> Posix.setFileMode tmpFilePath fileMode
+ case mDirFd of
+ Nothing -> Posix.rename tmpFilePath filePath
+ Just dirFd ->
+ withFilePath (takeFileName filePath) $ \cToFilePath ->
+ withFilePath (takeFileName tmpFilePath) $ \cTmpFilePath ->
+ throwErrnoIfMinus1Retry_ "atomicFileCreate - c_safe_renameat" $
+ c_renameat dirFd cTmpFilePath dirFd cToFilePath
+
+
+withDirectory :: MonadUnliftIO m => FilePath -> (DirFd -> m a) -> m a
+withDirectory dirPath = bracket (DirFd <$> openDir dirPath) closeDirectory
+
+withFileInDirectory ::
+ MonadUnliftIO m => DirFd -> FilePath -> IOMode -> (Handle -> m a) -> m a
+withFileInDirectory dirFd filePath iomode =
+ bracket (openFileFromDir dirFd filePath iomode) hClose
+
+
+-- | Create a temporary file for a matching possibly exiting target file that
+-- will be replaced in the future. Temporary file is meant to be renamed
+-- afterwards, thus it is only deleted upon error.
+--
+-- __Important__: Temporary file is not removed and file handle is not closed if
+-- there was no exception thrown by the supplied action.
+withBinaryTempFileFor ::
+ MonadUnliftIO m
+ => FilePath
+ -- ^ "For" file. It may exist or may not.
+ -> (FilePath -> Handle -> m a)
+ -> m a
+withBinaryTempFileFor filePath action =
+ bracketOnError
+ (liftIO (openBinaryTempFile dirPath tmpFileName))
+ (\(tmpFilePath, tmpFileHandle) ->
+ hClose tmpFileHandle >> liftIO (tryIO (removeFile tmpFilePath)))
+ (uncurry action)
+ where
+ dirPath = takeDirectory filePath
+ fileName = takeFileName filePath
+ tmpFileName = "." ++ fileName ++ ".tmp"
+
+-- | Returns `Nothing` if anonymous temporary file is not supported by the OS or
+-- the underlying file system can't handle that feature.
+withAnonymousBinaryTempFileFor ::
+ MonadUnliftIO m
+ => Maybe DirFd
+ -- ^ It is possible to open the temporary file in the context of a directory,
+ -- in such case supply its file descriptor. i.e. @openat@ will be used instead
+ -- of @open@
+ -> FilePath
+ -- ^ "For" file. The file may exist or may not.
+ -> IOMode
+ -> (Handle -> m a)
+ -> m (Maybe a)
+withAnonymousBinaryTempFileFor mDirFd filePath iomode action
+ | o_TMPFILE == o_TMPFILE_not_supported = pure Nothing
+ | otherwise =
+ trySupported $
+ bracket (openAnonymousTempFileFromDir mDirFd filePath iomode) hClose action
+ where
+ trySupported m =
+ tryIO m >>= \case
+ Right res -> pure $ Just res
+ Left exc
+ | ioeGetErrorType exc == UnsupportedOperation -> pure Nothing
+ Left exc -> throwIO exc
+
+withNonAnonymousBinaryTempFileFor ::
+ MonadUnliftIO m
+ => Maybe DirFd
+ -- ^ It is possible to open the temporary file in the context of a directory,
+ -- in such case supply its file descriptor. i.e. @openat@ will be used instead
+ -- of @open@
+ -> FilePath
+ -- ^ "For" file. The file may exist or may not.
+ -> IOMode
+ -> (FilePath -> Handle -> m a)
+ -> m a
+withNonAnonymousBinaryTempFileFor mDirFd filePath iomode action =
+ withBinaryTempFileFor filePath $ \tmpFilePath tmpFileHandle -> do
+ hClose tmpFileHandle
+ case mDirFd of
+ Nothing -> withBinaryFile tmpFilePath iomode (action tmpFilePath)
+ Just dirFd -> withFileInDirectory dirFd tmpFilePath iomode (action tmpFilePath)
+
+-- | Copy the contents of the file into the handle, but only if that file exists
+-- and either `ReadWriteMode` or `AppendMode` is specified. Returned are the
+-- file permissions of the original file so it can be set later when original
+-- gets overwritten atomically.
+copyFileHandle ::
+ MonadUnliftIO f => IOMode -> FilePath -> Handle -> f (Maybe FileMode)
+copyFileHandle iomode fromFilePath toHandle =
+ either (const Nothing) Just <$>
+ tryJust
+ (guard . isDoesNotExistError)
+ (do fileStatus <- liftIO $ Posix.getFileStatus fromFilePath
+ -- Whenever we are not overwriting an existing file, we also need a
+ -- copy of the file's contents
+ unless (iomode == WriteMode) $ do
+ withBinaryFile fromFilePath ReadMode (`copyHandleData` toHandle)
+ unless (iomode == AppendMode) $ hSeek toHandle AbsoluteSeek 0
+ -- Get the copy of source file permissions, but only whenever it exists
+ pure $ Posix.fileMode fileStatus)
+
+
+-- This is a copy of the internal function from `directory-1.3.3.2`. It became
+-- available only in directory-1.3.3.0 and is still internal, hence the
+-- duplication.
+copyHandleData :: MonadIO m => Handle -> Handle -> m ()
+copyHandleData hFrom hTo = liftIO $ allocaBytes bufferSize go
+ where
+ bufferSize = 131072 -- 128 KiB, as coreutils `cp` uses as of May 2014 (see ioblksize.h)
+ go buffer = do
+ count <- hGetBuf hFrom buffer bufferSize
+ when (count > 0) $ do
+ hPutBuf hTo buffer count
+ go buffer
+
+-- | Thread safe access to the file descriptor in the file handle
+withHandleFd :: Handle -> (Fd -> IO a) -> IO a
+withHandleFd h cb =
+ case h of
+ HandleFD.FileHandle _ mv ->
+ withMVar mv $ \HandleFD.Handle__{HandleFD.haDevice = dev} ->
+ case cast dev of
+ Just fd -> cb $ Fd $ FD.fdFD fd
+ Nothing -> error "withHandleFd: not a file handle"
+ HandleFD.DuplexHandle {} -> error "withHandleFd: not a file handle"
+
+-- | See `ensureFileDurable`
+ensureFileDurable :: MonadIO m => FilePath -> m ()
+ensureFileDurable filePath =
+ liftIO $
+ withDirectory (takeDirectory filePath) $ \dirFd ->
+ withFileInDirectory dirFd filePath ReadMode $ \fileHandle ->
+ liftIO $ do
+ fsyncFileHandle "ensureFileDurablePosix" fileHandle
+ -- NOTE: Here we are purposefully not fsyncing the directory if the file fails to fsync
+ fsyncDirectoryFd "ensureFileDurablePosix" dirFd
+
+
+
+-- | See `withBinaryFileDurable`
+withBinaryFileDurable ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+withBinaryFileDurable filePath iomode action =
+ case iomode of
+ ReadMode
+ -- We do not need to consider durable operations when we are in a
+ -- 'ReadMode', so we can use a regular `withBinaryFile`
+ -> withBinaryFile filePath iomode action
+ _ {- WriteMode, ReadWriteMode, AppendMode -}
+ ->
+ withDirectory (takeDirectory filePath) $ \dirFd ->
+ withFileInDirectory dirFd filePath iomode $ \tmpFileHandle -> do
+ res <- action tmpFileHandle
+ liftIO $ do
+ fsyncFileHandle "withBinaryFileDurablePosix" tmpFileHandle
+ -- NOTE: Here we are purposefully not fsyncing the directory if the file fails to fsync
+ fsyncDirectoryFd "withBinaryFileDurablePosix" dirFd
+ pure res
+
+-- | See `withBinaryFileDurableAtomic`
+withBinaryFileDurableAtomic ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+withBinaryFileDurableAtomic filePath iomode action =
+ case iomode of
+ ReadMode
+ -- We do not need to consider an atomic operation when we are in a
+ -- 'ReadMode', so we can use a regular `withBinaryFile`
+ -> withBinaryFile filePath iomode action
+ _ {- WriteMode, ReadWriteMode, AppendMode -}
+ ->
+ withDirectory (takeDirectory filePath) $ \dirFd -> do
+ mRes <- withAnonymousBinaryTempFileFor (Just dirFd) filePath iomode $
+ durableAtomicAction dirFd Nothing
+ case mRes of
+ Just res -> pure res
+ Nothing ->
+ withNonAnonymousBinaryTempFileFor (Just dirFd) filePath iomode $ \tmpFilePath ->
+ durableAtomicAction dirFd (Just tmpFilePath)
+ where
+ durableAtomicAction dirFd mTmpFilePath tmpFileHandle = do
+ mFileMode <- copyFileHandle iomode filePath tmpFileHandle
+ res <- action tmpFileHandle
+ liftIO $
+ atomicDurableTempFileRename
+ dirFd
+ mFileMode
+ tmpFileHandle
+ mTmpFilePath
+ filePath
+ pure res
+
+-- | See `withBinaryFileAtomic`
+withBinaryFileAtomic ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+withBinaryFileAtomic filePath iomode action =
+ case iomode of
+ ReadMode
+ -- We do not need to consider an atomic operation when we are in a
+ -- 'ReadMode', so we can use a regular `withBinaryFile`
+ -> withBinaryFile filePath iomode action
+ _ {- WriteMode, ReadWriteMode, AppendMode -}
+ -> do
+ mRes <-
+ withAnonymousBinaryTempFileFor Nothing filePath iomode $
+ atomicAction Nothing
+ case mRes of
+ Just res -> pure res
+ Nothing ->
+ withNonAnonymousBinaryTempFileFor Nothing filePath iomode $ \tmpFilePath ->
+ atomicAction (Just tmpFilePath)
+ where
+ atomicAction mTmpFilePath tmpFileHandle = do
+ let eTmpFile = maybe (Left tmpFileHandle) Right mTmpFilePath
+ mFileMode <- copyFileHandle iomode filePath tmpFileHandle
+ res <- action tmpFileHandle
+ liftIO $ atomicTempFileRename Nothing mFileMode eTmpFile filePath
+ pure res
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/src/UnliftIO/IO/File.hs new/unliftio-0.2.12/src/UnliftIO/IO/File.hs
--- old/unliftio-0.2.11/src/UnliftIO/IO/File.hs 1970-01-01 01:00:00.000000000 +0100
+++ new/unliftio-0.2.12/src/UnliftIO/IO/File.hs 2019-07-12 06:21:01.000000000 +0200
@@ -0,0 +1,278 @@
+{-# LANGUAGE CPP #-}
+{-|
+
+== Rationale
+
+This module offers functions to handle files that offer better durability and/or
+atomicity.
+
+== When to use functions in this module?
+
+Given the usage of this functions comes at a cost in performance, it is important to
+consider what are the use cases that are ideal for each of the functions.
+
+=== Not Durable and not Atomic
+
+For this use case, you want to use the regular functions:
+
+* 'withBinaryFile'
+* 'writeBinaryFile'
+
+The regular use case for this scenario happens when your program is dealing with outputs
+that are never going to be consumed again by your program. For example, imagine you have a
+program that generates sales reports for the last month, this is a report that can be
+generated quickly; you don't really care if the output file gets corrupted or lost at one
+particular execution of your program given that is cheap to execute the data export
+program a second time. In other words, your program doesn't /rely/ on the data contained
+in this file in order to work.
+
+=== Atomic but not Durable
+
+ Imagine a scenario where your program builds a temporary file that serves as an
+intermediate step to a bigger task, like Object files (@.o@) in a compilation process. The
+program will use an existing @.o@ file if it is present, or it will build one from scratch
+if it is not. The file is not really required, but if it is present, it *must* be valid
+and consistent. In this situation, you care about atomicity, but not durability. You can
+use the functions for such scenario:
+
+* 'withBinaryFileAtomic'
+* 'writeBinaryFileAtomic'
+
+__Note__ - there is a peculiar difference between regular file writing functionality and
+the one that is done atomically. Even if the orignal file is removed while it is being
+modified, because of atomicity, it will be restored with all modifications, if any. The
+reason for this is because a copy of the file was made prior to modifications and at the
+end the existing is atomically replaced. An important consequence of this fact is that
+whenever the folder containing the file which is being modified is removed, all bets are
+off and all atomic functions will result in an exception.
+
+=== Durable but not Atomic
+
+For this use case, you want to use the functions:
+
+* 'withBinaryFileDurable'
+* 'writeBinaryFileDurable'
+
+The regular use case for this scenario happens when your program deals with file
+modifications that must be guaranteed to be durable, but you don't care that changes are
+consistent. If you use this function, more than likely your program is ensuring
+consistency guarantees through other means, for example, SQLite uses the Write Ahead Log
+(WAL) algorithm to ensure changes are atomic at an application level.
+
+=== Durable and Atomic
+
+For this use case, you can use the functions:
+
+* 'withBinaryFileDurableAtomic'
+* 'writeBinaryFileDurableAtomic'
+
+The regular use case for this scenario happens when you want to ensure that after a
+program is executed, the modifications done to a file are guaranteed to be saved, and also
+that changes are rolled-back in case there is a failure (e.g. hard reboot, shutdown,
+etc).
+
+-}
+module UnliftIO.IO.File
+ ( writeBinaryFile
+ , writeBinaryFileAtomic
+ , writeBinaryFileDurable
+ , writeBinaryFileDurableAtomic
+ , withBinaryFile
+ , withBinaryFileAtomic
+ , withBinaryFileDurable
+ , withBinaryFileDurableAtomic
+ , ensureFileDurable
+ )
+ where
+
+import Data.ByteString as B (ByteString, writeFile)
+import Control.Monad.IO.Unlift
+import UnliftIO.IO (Handle, IOMode(..), withBinaryFile)
+
+#if WINDOWS
+
+
+ensureFileDurable = (`seq` pure ())
+
+writeBinaryFileDurable = writeBinaryFile
+writeBinaryFileDurableAtomic = writeBinaryFile
+writeBinaryFileAtomic = writeBinaryFile
+
+withBinaryFileDurable = withBinaryFile
+withBinaryFileDurableAtomic = withBinaryFile
+withBinaryFileAtomic = withBinaryFile
+
+#else
+
+import qualified Data.ByteString as B (hPut)
+import qualified UnliftIO.IO.File.Posix as Posix
+
+ensureFileDurable = Posix.ensureFileDurable
+
+writeBinaryFileDurable fp bytes =
+ liftIO $ withBinaryFileDurable fp WriteMode (`B.hPut` bytes)
+writeBinaryFileDurableAtomic fp bytes =
+ liftIO $ withBinaryFileDurableAtomic fp WriteMode (`B.hPut` bytes)
+writeBinaryFileAtomic fp bytes =
+ liftIO $ withBinaryFileAtomic fp WriteMode (`B.hPut` bytes)
+
+withBinaryFileDurable = Posix.withBinaryFileDurable
+withBinaryFileDurableAtomic = Posix.withBinaryFileDurableAtomic
+withBinaryFileAtomic = Posix.withBinaryFileAtomic
+#endif
+
+-- | After a file is closed, this function opens it again and executes @fsync()@
+-- internally on both the file and the directory that contains it. Note that this function
+-- is intended to work around the non-durability of existing file APIs, as opposed to
+-- being necessary for the API functions provided in this module.
+--
+-- [The effectiveness of calling this function is
+-- debatable](https://stackoverflow.com/questions/37288453/calling-fsync2-afte…,
+-- as it relies on internal implementation details at the Kernel level that might
+-- change. We argue that, despite this fact, calling this function may bring benefits in
+-- terms of durability.
+--
+-- This function does not provide the same guarantee as if you would open and modify a
+-- file using `withBinaryFileDurable` or `writeBinaryFileDurable`, since they ensure that
+-- the @fsync()@ is called before the file is closed, so if possible use those instead.
+--
+-- === Cross-Platform support
+--
+-- This function is a noop on Windows platforms.
+--
+-- @since 0.2.12
+ensureFileDurable :: MonadIO m => FilePath -> m ()
+-- Implementation is at the top of the module
+
+
+-- | Similar to 'writeBinaryFile', but it also ensures that changes executed to the file
+-- are guaranteed to be durable. It internally uses @fsync()@ and makes sure it
+-- synchronizes the file on disk.
+--
+-- === Cross-Platform support
+--
+-- This function behaves the same as 'RIO.writeBinaryFile' on Windows platforms.
+--
+-- @since 0.2.12
+writeBinaryFileDurable :: MonadIO m => FilePath -> ByteString -> m ()
+-- Implementation is at the top of the module
+
+-- | Similar to 'writeBinaryFile', but it also guarantes that changes executed to the file
+-- are durable, also, in case of failure, the modified file is never going to get
+-- corrupted. It internally uses @fsync()@ and makes sure it synchronizes the file on
+-- disk.
+--
+-- === Cross-Platform support
+--
+-- This function behaves the same as 'writeBinaryFile' on Windows platforms.
+--
+-- @since 0.2.12
+writeBinaryFileDurableAtomic :: MonadIO m => FilePath -> ByteString -> m ()
+-- Implementation is at the top of the module
+
+-- | Same as 'writeBinaryFileDurableAtomic', except it does not guarantee durability.
+--
+-- === Cross-Platform support
+--
+-- This function behaves the same as 'writeBinaryFile' on Windows platforms.
+--
+-- @since 0.2.12
+writeBinaryFileAtomic :: MonadIO m => FilePath -> ByteString -> m ()
+-- Implementation is at the top of the module
+
+-- | Opens a file with the following guarantees:
+--
+-- * It successfully closes the file in case of an asynchronous exception
+--
+-- * It reliably saves the file in the correct directory; including edge case situations
+-- like a different device being mounted to the current directory, or the current
+-- directory being renamed to some other name while the file is being used.
+--
+-- * It ensures durability by executing an @fsync()@ call before closing the file handle
+--
+-- === Cross-Platform support
+--
+-- This function behaves the same as 'System.IO.withBinaryFile' on Windows platforms.
+--
+-- @since 0.2.12
+withBinaryFileDurable ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+-- Implementation is at the top of the module
+
+-- | Opens a file with the following guarantees:
+--
+-- * It successfully closes the file in case of an asynchronous exception
+--
+-- * It reliably saves the file in the correct directory; including edge case situations
+-- like a different device being mounted to the current directory, or the current
+-- directory being renamed to some other name while the file is being used.
+--
+-- * It ensures durability by executing an @fsync()@ call before closing the file handle
+--
+-- * It keeps all changes in a temporary file, and after it is closed it atomically moves
+-- the temporary file to the original filepath, in case of catastrophic failure, the
+-- original file stays unaffected.
+--
+-- If you do not need durability but only atomicity, use `withBinaryFileAtomic` instead,
+-- which is faster as it does not perform @fsync()@.
+--
+-- __Important__ - Make sure not to close the `Handle`, it will be closed for you,
+-- otherwise it will result in @invalid argument (Bad file descriptor)@ exception.
+--
+-- === Performance Considerations
+--
+-- When using a writable but non-truncating 'IOMode' (i.e. 'ReadWriteMode' and
+-- 'AppendMode'), this function performs a copy operation of the specified input file to
+-- guarantee the original file is intact in case of a catastrophic failure (no partial
+-- writes). This approach may be prohibitive in scenarios where the input file is expected
+-- to be large in size.
+--
+-- === Cross-Platform support
+--
+-- This function behaves the same as 'System.IO.withBinaryFile' on Windows platforms.
+--
+-- @since 0.2.12
+withBinaryFileDurableAtomic ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+-- Implementation is at the top of the module
+
+
+-- | Perform an action on a new or existing file at the destination file path. If
+-- previously the file existed at the supplied file path then:
+--
+-- * in case of `WriteMode` it will be overwritten
+--
+-- * upon `ReadWriteMode` or `AppendMode` files contents will be copied over into a
+-- temporary file, thus making sure no corruption can happen to an existing file upon any
+-- failures, even catastrophic one, yet its contents are availble for modification.
+--
+-- * There is nothing atomic about `ReadMode`, so no special treatment there.
+--
+-- It is similar to `withBinaryFileDurableAtomic`, but without the durability part. It
+-- means that all modification can still disappear after it has been succesfully written
+-- due to some extreme event like an abrupt power loss, but the contents will not be
+-- corrupted in case when the file write did not end successfully.
+--
+-- The same performance caveats apply as for `withBinaryFileDurableAtomic` due to making a
+-- copy of the content of existing files during non-truncating writes.
+--
+-- __Important__ - Do not close the handle, otherwise it will result in @invalid argument
+-- (Bad file descriptor)@ exception
+--
+-- __Note__ - on Linux operating system and only with supported file systems an anonymous
+-- temporary file will be used while working on the file (see @O_TMPFILE@ in @man
+-- openat@). In case when such feature is not available or not supported a temporary file
+-- ".target-file-nameXXX.ext.tmp", where XXX is some random number, will be created
+-- alongside the target file in the same directory
+--
+-- @since 0.2.12
+withBinaryFileAtomic ::
+ MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m r) -> m r
+-- Implementation is at the top of the module
+
+
+-- | Lifted version of `B.writeFile`
+--
+-- @since 0.2.12
+writeBinaryFile :: MonadIO m => FilePath -> ByteString -> m ()
+writeBinaryFile fp = liftIO . B.writeFile fp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/test/UnliftIO/IO/FileSpec.hs new/unliftio-0.2.12/test/UnliftIO/IO/FileSpec.hs
--- old/unliftio-0.2.11/test/UnliftIO/IO/FileSpec.hs 1970-01-01 01:00:00.000000000 +0100
+++ new/unliftio-0.2.12/test/UnliftIO/IO/FileSpec.hs 2019-07-12 06:21:01.000000000 +0200
@@ -0,0 +1,201 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module UnliftIO.IO.FileSpec where
+
+import Test.Hspec
+-- Atomic/durable file writing is not supported on Windows.
+#ifndef WINDOWS
+import Control.Monad (forM_)
+import Data.Bool (bool)
+import System.FilePath ((</>))
+import Test.QuickCheck
+import UnliftIO.Directory
+import UnliftIO.Exception
+import UnliftIO.IO
+import UnliftIO.IO.File as File
+import UnliftIO.Temporary (withSystemTempDirectory)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy as BL
+#if __GLASGOW_HASKELL__ < 820
+import Data.Monoid
+#endif
+
+data ExpectedException =
+ ExpectedException
+ deriving (Show)
+
+instance Exception ExpectedException
+
+spec :: Spec
+spec = do
+ describe "ensureFileDurable" $
+ it "ensures a file is durable with an fsync" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> "ensure_file_durable"
+ writeFile fp "Hello World"
+ File.ensureFileDurable fp
+ contents <- B.readFile fp
+ contents `shouldBe` "Hello World"
+ withBinaryFileSpec False "withBinaryFile" withBinaryFile
+ writeBinaryFileSpec "writeBinaryFile" writeBinaryFile
+ -- Above two specs are validating the specs behavior by applying to
+ -- known good implementations
+ withBinaryFileSpec True "withBinaryFileAtomic" File.withBinaryFileAtomic
+ writeBinaryFileSpec "writeBinaryFileAtomic" File.writeBinaryFileAtomic
+ withBinaryFileSpec False "withBinaryFileDurable" File.withBinaryFileDurable
+ writeBinaryFileSpec "writeBinaryFileDurable" File.writeBinaryFileDurable
+ withBinaryFileSpec True "withBinaryFileDurableAtomic" File.withBinaryFileDurableAtomic
+ writeBinaryFileSpec "writeBinaryFileDurableAtomic" File.writeBinaryFileDurableAtomic
+
+writeFileUtf8 fp str = withBinaryFile fp WriteMode (`BB.hPutBuilder` BB.stringUtf8 str)
+
+withBinaryFileSpec ::
+ Bool -- ^ Should we test atomicity
+ -> String
+ -> (forall a. FilePath -> IOMode -> (Handle -> IO a) -> IO a)
+ -> Spec
+withBinaryFileSpec atomic fname withFileTestable = do
+ let hello = "Hello World"
+ helloString = "Hello World"
+ writeHello fp = writeFileUtf8 fp helloString
+ -- Create a file, write "Hello World" into it and apply the action.
+ withHelloFileTestable fp iomode action = do
+ writeHello fp
+ withFileTestable fp iomode action
+ goodbye = "Goodbye yall"
+ modifiedPermissions =
+ setOwnerExecutable True $
+ setOwnerReadable True $ setOwnerWritable True emptyPermissions
+ describe fname $ do
+ it "read" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-read"
+ withHelloFileTestable fp ReadWriteMode (`B.hGet` B.length hello) `shouldReturn`
+ hello
+ it "write" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-write"
+ withHelloFileTestable fp WriteMode (`B.hPut` goodbye)
+ B.readFile fp `shouldReturn` goodbye
+ it "read/write" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-read-write"
+ withHelloFileTestable fp ReadWriteMode $ \h -> do
+ B.hGetLine h `shouldReturn` hello
+ B.hPut h goodbye
+ B.readFile fp `shouldReturn` (hello <> goodbye)
+ it "append" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-append"
+ privet = "Привет Мир" -- some unicode won't hurt
+ encodeUtf8 = BL.toStrict . BB.toLazyByteString . BB.stringUtf8
+ writeFileUtf8 fp privet
+ setPermissions fp modifiedPermissions
+ withFileTestable fp AppendMode $ \h -> B.hPut h goodbye
+ B.readFile fp `shouldReturn` (encodeUtf8 privet <> goodbye)
+ it "sub-directory" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let subDir = dir </> fname ++ "-sub-directory"
+ fp = subDir </> "test.file"
+ createDirectoryIfMissing True subDir
+ withHelloFileTestable fp ReadWriteMode $ \h -> do
+ B.hGetLine h `shouldReturn` hello
+ B.hPut h goodbye
+ B.readFile fp `shouldReturn` (hello <> goodbye)
+ it "relative-directory" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let relDir = fname ++ "-relative-directory"
+ subDir = dir </> relDir
+ fp = relDir </> "test.file"
+ createDirectoryIfMissing True subDir
+ withCurrentDirectoryCompat dir $ do
+ withHelloFileTestable fp ReadWriteMode $ \h -> do
+ B.hGetLine h `shouldReturn` hello
+ B.hPut h goodbye
+ B.readFile fp `shouldReturn` (hello <> goodbye)
+ it "modified-permissions" $
+ forM_ [WriteMode, ReadWriteMode, AppendMode] $ \iomode ->
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-modified-permissions"
+ writeHello fp
+ setPermissions fp modifiedPermissions
+ withFileTestable fp iomode $ \h -> B.hPut h goodbye
+ getPermissions fp `shouldReturn` modifiedPermissions
+ it "exception - Does not corrupt files" $
+ bool expectFailure property atomic $ -- should fail for non-atomic
+ forM_ [WriteMode, ReadWriteMode, AppendMode] $ \iomode ->
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-exception"
+ _ :: Either ExpectedException () <-
+ try $
+ withHelloFileTestable fp iomode $ \h -> do
+ B.hPut h goodbye
+ throwIO ExpectedException
+ B.readFile fp `shouldReturn` hello
+ it "exception - Does not leave files behind" $
+ bool expectFailure property atomic $ -- should fail for non-atomic
+ forM_ [WriteMode, ReadWriteMode, AppendMode] $ \iomode ->
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-exception"
+ _ :: Either ExpectedException () <-
+ try $
+ withFileTestable fp iomode $ \h -> do
+ B.hPut h goodbye
+ throwIO ExpectedException
+ doesFileExist fp `shouldReturn` False
+ listDirectoryCompat dir `shouldReturn` []
+ it "delete - file" $
+ bool expectFailure property atomic $ -- should fail for non-atomic
+ forM_ [WriteMode, ReadWriteMode, AppendMode] $ \iomode ->
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-delete"
+ withHelloFileTestable fp iomode $ \h -> do
+ removeFile fp
+ B.hPut h goodbye
+ doesFileExist fp `shouldReturn` True
+
+writeBinaryFileSpec :: String -> (FilePath -> B.ByteString -> IO ()) -> SpecWith ()
+writeBinaryFileSpec fname writeFileTestable = do
+ let hello = "Hello World"
+ describe fname $ do
+ it "write" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-write"
+ writeFileTestable fp hello
+ B.readFile fp `shouldReturn` hello
+ it "default-permissions" $
+ withSystemTempDirectory "rio" $ \dir -> do
+ let fp = dir </> fname ++ "-default-permissions"
+ defaultPermissions =
+ setOwnerReadable True $ setOwnerWritable True emptyPermissions
+ writeFileTestable fp hello
+ getPermissions fp `shouldReturn` defaultPermissions
+
+
+listDirectoryCompat :: FilePath -> IO [FilePath]
+#if MIN_VERSION_directory(1,2,5)
+listDirectoryCompat = listDirectory
+#else
+listDirectoryCompat path =
+ filter f <$> getDirectoryContents path
+ where f filename = filename /= "." && filename /= ".."
+#endif
+
+withCurrentDirectoryCompat :: FilePath -> IO a -> IO a
+#if MIN_VERSION_directory(1,2,3)
+withCurrentDirectoryCompat = withCurrentDirectory
+#else
+withCurrentDirectoryCompat dir action =
+ bracket getCurrentDirectory setCurrentDirectory $ \ _ -> do
+ setCurrentDirectory dir
+ action
+#endif
+
+#else
+spec :: Spec
+spec = pure ()
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.11/unliftio.cabal new/unliftio-0.2.12/unliftio.cabal
--- old/unliftio-0.2.11/unliftio.cabal 2019-06-07 12:40:40.000000000 +0200
+++ new/unliftio-0.2.12/unliftio.cabal 2019-07-12 06:21:15.000000000 +0200
@@ -1,13 +1,13 @@
cabal-version: 1.12
--- This file has been generated from package.yaml by hpack version 0.31.1.
+-- This file has been generated from package.yaml by hpack version 0.31.2.
--
-- see: https://github.com/sol/hpack
--
--- hash: 9b54d473debcf0958351a2c8a7924ed9a8d3504243c348545109ffe72b005683
+-- hash: 55a1160a6cc39aa1529ed95fe90e85ac31d632ee8ea1f31f06cb77bd2502de5b
name: unliftio
-version: 0.2.11
+version: 0.2.12
synopsis: The MonadUnliftIO typeclass for unlifting monads to IO (batteries included)
description: Please see the documentation and README at <https://www.stackage.org/package/unliftio>
category: Control
@@ -28,7 +28,8 @@
ghc-options: -fwarn-incomplete-uni-patterns
build-depends:
async >2.1.1
- , base >=4.7 && <5
+ , base >=4.8 && <5
+ , bytestring
, deepseq
, directory
, filepath
@@ -46,14 +47,20 @@
build-depends:
nats
if os(darwin)
+ other-modules:
+ UnliftIO.IO.File.Posix
c-sources:
cbits/time-osx.c
+ cbits/file-posix.c
else
if os(windows)
c-sources:
cbits/time-windows.c
else
+ other-modules:
+ UnliftIO.IO.File.Posix
c-sources:
+ cbits/file-posix.c
cbits/time-posix.c
exposed-modules:
UnliftIO
@@ -66,6 +73,7 @@
UnliftIO.Foreign
UnliftIO.Internals.Async
UnliftIO.IO
+ UnliftIO.IO.File
UnliftIO.IORef
UnliftIO.Memoize
UnliftIO.MVar
@@ -85,7 +93,8 @@
build-depends:
QuickCheck
, async >2.1.1
- , base >=4.7 && <5
+ , base >=4.8 && <5
+ , bytestring
, containers
, deepseq
, directory
@@ -105,6 +114,7 @@
other-modules:
UnliftIO.AsyncSpec
UnliftIO.ExceptionSpec
+ UnliftIO.IO.FileSpec
UnliftIO.IOSpec
UnliftIO.MemoizeSpec
UnliftIO.PooledAsyncSpec
@@ -121,7 +131,8 @@
ghc-options: -O2 -threaded -rtsopts
build-depends:
async >2.1.1
- , base >=4.7 && <5
+ , base >=4.8 && <5
+ , bytestring
, deepseq
, directory
, filepath
1
0
Hello community,
here is the log from the commit of package ghc-typed-process for openSUSE:Factory checked in at 2019-07-29 17:27:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-typed-process (Old)
and /work/SRC/openSUSE:Factory/.ghc-typed-process.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-typed-process"
Mon Jul 29 17:27:08 2019 rev:10 rq:715422 version:0.2.6.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-typed-process/ghc-typed-process.changes 2019-06-30 10:21:46.835646227 +0200
+++ /work/SRC/openSUSE:Factory/.ghc-typed-process.new.4126/ghc-typed-process.changes 2019-07-29 17:27:10.046284974 +0200
@@ -1,0 +2,9 @@
+Thu Jul 4 02:03:36 UTC 2019 - psimons(a)suse.com
+
+- Update typed-process to version 0.2.6.0.
+ ## Unreleased
+
+ * The cleanup thread applies an `unmask` to the actions which wait for a
+ process to exit, allowing the action to be interruptible.
+
+-------------------------------------------------------------------
Old:
----
typed-process-0.2.5.0.tar.gz
New:
----
typed-process-0.2.6.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-typed-process.spec ++++++
--- /var/tmp/diff_new_pack.ixaN7f/_old 2019-07-29 17:27:11.094284586 +0200
+++ /var/tmp/diff_new_pack.ixaN7f/_new 2019-07-29 17:27:11.102284583 +0200
@@ -19,7 +19,7 @@
%global pkg_name typed-process
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.2.5.0
+Version: 0.2.6.0
Release: 0
Summary: Run external processes, with strong typing of streams
License: MIT
@@ -33,6 +33,7 @@
BuildRequires: ghc-rpm-macros
BuildRequires: ghc-stm-devel
BuildRequires: ghc-transformers-devel
+BuildRequires: ghc-unliftio-core-devel
%if %{with tests}
BuildRequires: ghc-base64-bytestring-devel
BuildRequires: ghc-hspec-devel
++++++ typed-process-0.2.5.0.tar.gz -> typed-process-0.2.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typed-process-0.2.5.0/ChangeLog.md new/typed-process-0.2.6.0/ChangeLog.md
--- old/typed-process-0.2.5.0/ChangeLog.md 2019-06-26 06:52:47.000000000 +0200
+++ new/typed-process-0.2.6.0/ChangeLog.md 2019-07-02 16:13:24.000000000 +0200
@@ -1,5 +1,10 @@
# ChangeLog for typed-process
+## Unreleased
+
+* The cleanup thread applies an `unmask` to the actions which wait for a
+ process to exit, allowing the action to be interruptible.
+
## 0.2.5.0
* Add a `nullStream` [#24](https://github.com/fpco/typed-process/pull/24)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typed-process-0.2.5.0/src/System/Process/Typed.hs new/typed-process-0.2.6.0/src/System/Process/Typed.hs
--- old/typed-process-0.2.5.0/src/System/Process/Typed.hs 2019-06-26 06:52:47.000000000 +0200
+++ new/typed-process-0.2.6.0/src/System/Process/Typed.hs 2019-07-03 06:58:46.000000000 +0200
@@ -97,7 +97,8 @@
import qualified Data.ByteString as S
import Data.ByteString.Lazy.Internal (defaultChunkSize)
-import Control.Exception (assert, evaluate, throwIO, Exception, SomeException, finally, bracket, onException, catch, try)
+import qualified Control.Exception as E
+import Control.Exception hiding (bracket, finally)
import Control.Monad (void)
import Control.Monad.IO.Class
import qualified System.Process as P
@@ -105,7 +106,7 @@
import System.IO (Handle, hClose, IOMode(ReadWriteMode), withBinaryFile)
import System.IO.Error (isPermissionError)
import Control.Concurrent (threadDelay)
-import Control.Concurrent.Async (async, cancel, waitCatch)
+import Control.Concurrent.Async (async, asyncWithUnmask, cancel, waitCatch)
import Control.Concurrent.STM (newEmptyTMVarIO, atomically, putTMVar, TMVar, readTMVar, tryReadTMVar, STM, tryPutTMVar, throwSTM, catchSTM)
import System.Exit (ExitCode (ExitSuccess))
import System.Process.Typed.Internal
@@ -113,6 +114,7 @@
import qualified Data.ByteString.Lazy.Char8 as L8
import Data.String (IsString (fromString))
import GHC.RTS.Flags (getConcFlags, ctxtSwitchTime)
+import Control.Monad.IO.Unlift
#if MIN_VERSION_process(1, 4, 0) && !WINDOWS
import System.Posix.Types (GroupID, UserID)
@@ -667,8 +669,8 @@
<*> ssCreate pcStderr pConfig merrH
pExitCode <- newEmptyTMVarIO
- waitingThread <- async $ do
- ec <-
+ waitingThread <- asyncWithUnmask $ \unmask -> do
+ ec <- unmask $ -- make sure the masking state from a bracket isn't inherited
if multiThreadedRuntime
then P.waitForProcess pHandle
else do
@@ -759,10 +761,10 @@
-- <https://github.com/fpco/typed-process/issues/25>.
--
-- @since 0.2.5.0
-withProcessTerm
- :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcessTerm :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcessTerm config = bracket (startProcess config) stopProcess
-- | Uses the bracket pattern to call 'startProcess'. Unlike
@@ -771,10 +773,10 @@
-- inner function throws an exception.
--
-- @since 0.2.5.0
-withProcessWait
- :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcessWait :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcessWait config f =
bracket
(startProcess config)
@@ -784,19 +786,20 @@
-- | Deprecated synonym for 'withProcessTerm'.
--
-- @since 0.1.0.0
-withProcess :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcess :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcess = withProcessTerm
{-# DEPRECATED withProcess "Please consider using withProcessWait, or instead use withProcessTerm" #-}
-- | Same as 'withProcessTerm', but also calls 'checkExitCode'
--
-- @since 0.2.5.0
-withProcessTerm_
- :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcessTerm_ :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcessTerm_ config = bracket
(startProcess config)
(\p -> stopProcess p `finally` checkExitCode p)
@@ -804,10 +807,10 @@
-- | Same as 'withProcessWait', but also calls 'checkExitCode'
--
-- @since 0.2.5.0
-withProcessWait_
- :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcessWait_ :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcessWait_ config f = bracket
(startProcess config)
stopProcess
@@ -816,9 +819,10 @@
-- | Deprecated synonym for 'withProcessTerm_'.
--
-- @since 0.1.0.0
-withProcess_ :: ProcessConfig stdin stdout stderr
- -> (Process stdin stdout stderr -> IO a)
- -> IO a
+withProcess_ :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdout stderr
+ -> (Process stdin stdout stderr -> m a)
+ -> m a
withProcess_ = withProcessTerm_
{-# DEPRECATED withProcess_ "Please consider using withProcessWait_, or instead use withProcessTerm_" #-}
@@ -933,10 +937,10 @@
where
pc' = setStderr byteStringOutput pc
-withProcessInterleave
- :: ProcessConfig stdin stdoutIgnored stderrIgnored
- -> (Process stdin (STM L.ByteString) () -> IO a)
- -> IO a
+withProcessInterleave :: (MonadUnliftIO m)
+ => ProcessConfig stdin stdoutIgnored stderrIgnored
+ -> (Process stdin (STM L.ByteString) () -> m a)
+ -> m a
withProcessInterleave pc inner =
-- Create a pipe to be shared for both stdout and stderr
bracket P.createPipe (\(r, w) -> hClose r >> hClose w) $ \(readEnd, writeEnd) -> do
@@ -949,7 +953,7 @@
withProcess pc' $ \p -> do
-- Now that the process is forked, close the writer end of this
-- pipe, otherwise the reader end will never give an EOF.
- hClose writeEnd
+ liftIO $ hClose writeEnd
inner p
-- | Same as 'readProcess', but interleaves stderr with stdout.
@@ -1142,3 +1146,9 @@
-- @since 0.1.1
unsafeProcessHandle :: Process stdin stdout stderr -> P.ProcessHandle
unsafeProcessHandle = pHandle
+
+bracket :: MonadUnliftIO m => IO a -> (a -> IO b) -> (a -> m c) -> m c
+bracket before after thing = withRunInIO $ \run -> E.bracket before after (run . thing)
+
+finally :: MonadUnliftIO m => m a -> IO () -> m a
+finally thing after = withRunInIO $ \run -> E.finally (run thing) after
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typed-process-0.2.5.0/test/System/Process/TypedSpec.hs new/typed-process-0.2.6.0/test/System/Process/TypedSpec.hs
--- old/typed-process-0.2.5.0/test/System/Process/TypedSpec.hs 2019-06-26 06:52:47.000000000 +0200
+++ new/typed-process-0.2.6.0/test/System/Process/TypedSpec.hs 2019-07-03 06:58:46.000000000 +0200
@@ -112,14 +112,14 @@
raw <- S.readFile fp
encoded `shouldBe` B64.encode raw
- describe "withProcessWait" $ do
+ describe "withProcessWait" $
it "succeeds with sleep" $ do
p <- withProcessWait (proc "sleep" ["1"]) pure
- checkExitCode p
+ checkExitCode p :: IO ()
- describe "withProcessWait_" $ do
- it "succeeds with sleep" $ do
- withProcessWait_ (proc "sleep" ["1"]) $ const $ pure ()
+ describe "withProcessWait_" $
+ it "succeeds with sleep"
+ ((withProcessWait_ (proc "sleep" ["1"]) $ const $ pure ()) :: IO ())
-- These tests fail on older GHCs/process package versions
-- because, apparently, waitForProcess isn't interruptible. See
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typed-process-0.2.5.0/typed-process.cabal new/typed-process-0.2.6.0/typed-process.cabal
--- old/typed-process-0.2.5.0/typed-process.cabal 2019-06-25 10:04:51.000000000 +0200
+++ new/typed-process-0.2.6.0/typed-process.cabal 2019-07-02 07:42:38.000000000 +0200
@@ -4,10 +4,10 @@
--
-- see: https://github.com/sol/hpack
--
--- hash: ad27eee8ecda9f23b7e99ea05885ad76c916b5210115a132a56a28c79437d01c
+-- hash: f8fdbd0397d67fa0c8d6c96e3e95d3d6eb56d94fc13f0350fc60ff855d44d671
name: typed-process
-version: 0.2.5.0
+version: 0.2.6.0
synopsis: Run external processes, with strong typing of streams
description: Please see the tutorial at <https://haskell-lang.org/library/typed-process>
category: System
@@ -41,6 +41,7 @@
, process >=1.2
, stm
, transformers
+ , unliftio-core
if os(windows)
cpp-options: -DWINDOWS
default-language: Haskell2010
@@ -65,6 +66,7 @@
, temporary
, transformers
, typed-process
+ , unliftio-core
default-language: Haskell2010
test-suite typed-process-test-single-threaded
@@ -86,4 +88,5 @@
, temporary
, transformers
, typed-process
+ , unliftio-core
default-language: Haskell2010
1
0
Hello community,
here is the log from the commit of package ghc-store for openSUSE:Factory checked in at 2019-07-29 17:27:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-store (Old)
and /work/SRC/openSUSE:Factory/.ghc-store.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-store"
Mon Jul 29 17:27:00 2019 rev:9 rq:715421 version:0.5.1.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-store/ghc-store.changes 2019-06-12 13:18:45.172566626 +0200
+++ /work/SRC/openSUSE:Factory/.ghc-store.new.4126/ghc-store.changes 2019-07-29 17:27:03.946287232 +0200
@@ -1,0 +2,9 @@
+Mon Jul 8 02:01:12 UTC 2019 - psimons(a)suse.com
+
+- Update store to version 0.5.1.2.
+ ## 0.5.1.2
+
+ * Fixes compilation with GHC < 8.0. See
+ [#142](https://github.com/fpco/store/issues/142).
+
+-------------------------------------------------------------------
Old:
----
store-0.5.1.1.tar.gz
New:
----
store-0.5.1.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-store.spec ++++++
--- /var/tmp/diff_new_pack.8fXGCG/_old 2019-07-29 17:27:04.386287069 +0200
+++ /var/tmp/diff_new_pack.8fXGCG/_new 2019-07-29 17:27:04.390287068 +0200
@@ -19,7 +19,7 @@
%global pkg_name store
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.5.1.1
+Version: 0.5.1.2
Release: 0
Summary: Fast binary serialization
License: MIT
++++++ store-0.5.1.1.tar.gz -> store-0.5.1.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/store-0.5.1.1/ChangeLog.md new/store-0.5.1.2/ChangeLog.md
--- old/store-0.5.1.1/ChangeLog.md 2019-05-21 07:04:38.000000000 +0200
+++ new/store-0.5.1.2/ChangeLog.md 2019-07-07 05:32:21.000000000 +0200
@@ -1,5 +1,10 @@
# ChangeLog
+## 0.5.1.2
+
+* Fixes compilation with GHC < 8.0. See
+ [#142](https://github.com/fpco/store/issues/142).
+
## 0.5.1.1
* Update to the instances for generics, to improve error messages for
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/store-0.5.1.1/src/Data/Store/Impl.hs new/store-0.5.1.2/src/Data/Store/Impl.hs
--- old/store-0.5.1.1/src/Data/Store/Impl.hs 2019-05-21 07:02:09.000000000 +0200
+++ new/store-0.5.1.2/src/Data/Store/Impl.hs 2019-07-07 05:28:15.000000000 +0200
@@ -287,13 +287,16 @@
type FitsInByte n = FitsInByteResult (n <=? 255)
type family FitsInByteResult (b :: Bool) :: Constraint where
- FitsInByteResult True = ()
- FitsInByteResult False = TypeErrorMessage
+ FitsInByteResult 'True = ()
+ FitsInByteResult 'False = TypeErrorMessage
"Generic deriving of Store instances can only be used on datatypes with fewer than 256 constructors."
type family TypeErrorMessage (a :: Symbol) :: Constraint where
#if MIN_VERSION_base(4,9,0)
TypeErrorMessage a = TypeError (Text a)
+-- GHC < 8.0 does not support empty closed type families
+#elif __GLASGOW_HASKELL__ < 800
+ TypeErrorMessage a = a ~ ""
#endif
-- Similarly to splitting up the generic class into multiple classes, we
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/store-0.5.1.1/store.cabal new/store-0.5.1.2/store.cabal
--- old/store-0.5.1.1/store.cabal 2019-05-21 07:05:18.000000000 +0200
+++ new/store-0.5.1.2/store.cabal 2019-07-07 05:33:20.000000000 +0200
@@ -4,10 +4,10 @@
--
-- see: https://github.com/sol/hpack
--
--- hash: a18e85521a544ee521dc7788e9b2194c7c3ec0efbeb6092e401782d962ea22d3
+-- hash: 432401eddc329fdeadc94cd6a50d7641756074a9537ef2306c874619e22c33af
name: store
-version: 0.5.1.1
+version: 0.5.1.2
synopsis: Fast binary serialization
category: Serialization, Data
homepage: https://github.com/fpco/store#readme
1
0
Hello community,
here is the log from the commit of package ghc-skylighting-core for openSUSE:Factory checked in at 2019-07-29 17:26:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-skylighting-core (Old)
and /work/SRC/openSUSE:Factory/.ghc-skylighting-core.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-skylighting-core"
Mon Jul 29 17:26:53 2019 rev:9 rq:715420 version:0.8.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-skylighting-core/ghc-skylighting-core.changes 2019-06-19 21:12:50.518768248 +0200
+++ /work/SRC/openSUSE:Factory/.ghc-skylighting-core.new.4126/ghc-skylighting-core.changes 2019-07-29 17:27:02.486287773 +0200
@@ -1,0 +2,21 @@
+Mon Jul 15 02:01:57 UTC 2019 - psimons(a)suse.com
+
+- Update skylighting-core to version 0.8.2.
+ ## 0.8.2 -- 2019-07-14
+
+ * Change matchRegex so it gives "no match" on a regex error
+ instead of raising an exception. This seems to be how Kate
+ works. Fixes an error on long integer literals (#81).
+
+ ## 0.8.1.2 -- 2019-07-14
+
+ * Fix HlCChar for one-character octal escapes like '\0' (#82).
+ Due to a bug in pCStringChar, only multi-character octal
+ escapes were being recognized. This affects not just C
+ highlighting, but all of the following highlighters which
+ use HlCChar: fasm eiffel pike objectivec ruby vhdl scala
+ java jsp nasm protobuf pure go objectivecpp gnuassembler povray
+ actionscript c cs opencl boo rhtml elixir. This fixes a
+ regression introduced in version 0.3.1.
+
+-------------------------------------------------------------------
Old:
----
skylighting-core-0.8.1.1.tar.gz
New:
----
skylighting-core-0.8.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-skylighting-core.spec ++++++
--- /var/tmp/diff_new_pack.bt6y4d/_old 2019-07-29 17:27:03.686287328 +0200
+++ /var/tmp/diff_new_pack.bt6y4d/_new 2019-07-29 17:27:03.690287327 +0200
@@ -19,7 +19,7 @@
%global pkg_name skylighting-core
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.8.1.1
+Version: 0.8.2
Release: 0
Summary: Syntax highlighting library
License: BSD-3-Clause
++++++ skylighting-core-0.8.1.1.tar.gz -> skylighting-core-0.8.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/changelog.md new/skylighting-core-0.8.2/changelog.md
--- old/skylighting-core-0.8.1.1/changelog.md 2019-06-14 03:43:56.000000000 +0200
+++ new/skylighting-core-0.8.2/changelog.md 2019-07-14 19:04:54.000000000 +0200
@@ -1,5 +1,22 @@
# Revision history for skylighting and skylighting-core
+## 0.8.2 -- 2019-07-14
+
+ * Change matchRegex so it gives "no match" on a regex error
+ instead of raising an exception. This seems to be how Kate
+ works. Fixes an error on long integer literals (#81).
+
+## 0.8.1.2 -- 2019-07-14
+
+ * Fix HlCChar for one-character octal escapes like '\0' (#82).
+ Due to a bug in pCStringChar, only multi-character octal
+ escapes were being recognized. This affects not just C
+ highlighting, but all of the following highlighters which
+ use HlCChar: fasm eiffel pike objectivec ruby vhdl scala
+ java jsp nasm protobuf pure go objectivecpp gnuassembler povray
+ actionscript c cs opencl boo rhtml elixir. This fixes a
+ regression introduced in version 0.3.1.
+
## 0.8.1.1 -- 2019-06-13
* Improved LaTeX escaping (#78).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/skylighting-core.cabal new/skylighting-core-0.8.2/skylighting-core.cabal
--- old/skylighting-core-0.8.1.1/skylighting-core.cabal 2019-06-14 03:43:56.000000000 +0200
+++ new/skylighting-core-0.8.2/skylighting-core.cabal 2019-07-14 19:04:00.000000000 +0200
@@ -1,5 +1,5 @@
name: skylighting-core
-version: 0.8.1.1
+version: 0.8.2
synopsis: syntax highlighting library
description: Skylighting is a syntax highlighting library.
It derives its tokenizers from XML syntax
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/src/Skylighting/Format/HTML.hs new/skylighting-core-0.8.2/src/Skylighting/Format/HTML.hs
--- old/skylighting-core-0.8.1.1/src/Skylighting/Format/HTML.hs 2019-05-30 17:44:51.000000000 +0200
+++ new/skylighting-core-0.8.2/src/Skylighting/Format/HTML.hs 2019-07-14 18:19:49.000000000 +0200
@@ -167,23 +167,22 @@
" padding-left: 4px; }"
]
divspec = [
- "code.sourceCode > span { display: inline-block; line-height: 1.25; }"
+ "pre > code.sourceCode { white-space: pre; position: relative; }" -- position relative needed for relative contents
+ , "pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }"
+ , "pre > code.sourceCode > span:empty { height: 1.2em; }" -- correct empty line height
, "code.sourceCode > span { color: inherit; text-decoration: inherit; }"
- , "code.sourceCode > span:empty { height: 1.2em; }" -- correct empty line height
- , ".sourceCode { overflow: visible; }" -- needed for line numbers
- , "code.sourceCode { white-space: pre; position: relative; }" -- position relative needed for relative contents
, "div.sourceCode { margin: 1em 0; }" -- Collapse neighbours correctly
, "pre.sourceCode { margin: 0; }" -- Collapse neighbours correctly
, "@media screen {"
, "div.sourceCode { overflow: auto; }" -- do not overflow on screen
, "}"
, "@media print {"
- , "code.sourceCode { white-space: pre-wrap; }"
- , "code.sourceCode > span { text-indent: -5em; padding-left: 5em; }"
+ , "pre > code.sourceCode { white-space: pre-wrap; }"
+ , "pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }"
, "}"
]
linkspec = [ "@media screen {"
- , "code.sourceCode > span > a:first-child::before { text-decoration: underline; }"
+ , "pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }"
, "}"
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/src/Skylighting/Regex.hs new/skylighting-core-0.8.2/src/Skylighting/Regex.hs
--- old/skylighting-core-0.8.1.1/src/Skylighting/Regex.hs 2018-03-03 17:47:19.000000000 +0100
+++ new/skylighting-core-0.8.2/src/Skylighting/Regex.hs 2019-07-14 18:56:37.000000000 +0200
@@ -94,8 +94,9 @@
matchRegex r s = case unsafePerformIO (regexec r s) of
Right (Just (_, mat, _ , capts)) ->
Just (mat : capts)
- Right Nothing -> Nothing
- Left (_rc, msg) -> E.throw $ RegexException msg
+ Right Nothing -> Nothing
+ -- treat match error as no match, like Kate: #81
+ Left (_rc, _msg) -> Nothing
-- functions to marshall bytestrings to text
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/src/Skylighting/Tokenizer.hs new/skylighting-core-0.8.2/src/Skylighting/Tokenizer.hs
--- old/skylighting-core-0.8.1.1/src/Skylighting/Tokenizer.hs 2019-06-04 08:44:17.000000000 +0200
+++ new/skylighting-core-0.8.2/src/Skylighting/Tokenizer.hs 2019-07-14 18:24:21.000000000 +0200
@@ -624,7 +624,7 @@
next <- A.anyChar
case next of
c | c == 'x' || c == 'X' -> () <$ A.takeWhile1 (A.inClass "0-9a-fA-F")
- | c == '0' -> () <$ A.takeWhile1 (A.inClass "0-7")
+ | c == '0' -> () <$ A.takeWhile (A.inClass "0-7")
| A.inClass "abefnrtv\"'?\\" c -> return ()
| otherwise -> mzero
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/skylighting-core-0.8.1.1/test/test-skylighting.hs new/skylighting-core-0.8.2/test/test-skylighting.hs
--- old/skylighting-core-0.8.1.1/test/test-skylighting.hs 2019-06-04 08:44:17.000000000 +0200
+++ new/skylighting-core-0.8.2/test/test-skylighting.hs 2019-07-14 19:01:29.000000000 +0200
@@ -90,7 +90,9 @@
let perl = maybe (error "could not find Perl syntax") id
(lookupSyntax "Perl" sMap)
cpp = maybe (error "could not find CPP syntax") id
- (lookupSyntax "cpp" sMap) in
+ (lookupSyntax "cpp" sMap)
+ c = maybe (error "could not find C syntax") id
+ (lookupSyntax "c" sMap) in
[ testCase "perl NUL case" $ Right
[[(KeywordTok,"s\NUL")
,(OtherTok,"b")
@@ -145,8 +147,15 @@
"0.1f\n1.0f\n-0.1f\n-1.0F\n-1.0L\n1e3\n-15e+3\n0.f\n1.F\n1.E3"
, testCase "cpp identifier (#76)" $ Right
[ [ (NormalTok,"ng_or") ]
- ] @=? tokenize defConfig cpp
- "ng_or"
+ ] @=? tokenize defConfig cpp "ng_or"
+
+ , testCase "c '\\0' (#82)" $ Right
+ [ [ (CharTok,"'\\0'") ]
+ ] @=? tokenize defConfig c "'\\0'"
+
+ , testCase "c very long integer (#81)" $ Right
+ [ [ (DecValTok, "1111111111111111111111") ]
+ ] @=? tokenize defConfig c "1111111111111111111111"
]
]
1
0