Merge branch 'master' into core-updates
This commit is contained in:
		
						commit
						062c7e43ed
					
				
					 30 changed files with 2567 additions and 1314 deletions
				
			
		| 
						 | 
				
			
			@ -4791,7 +4791,9 @@ The general syntax is:
 | 
			
		|||
guix hash @var{option} @var{file}
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
@command{guix hash} has the following options:
 | 
			
		||||
When @var{file} is @code{-} (a hyphen), @command{guix hash} computes the
 | 
			
		||||
hash of data read from standard input.  @command{guix hash} has the
 | 
			
		||||
following options:
 | 
			
		||||
 | 
			
		||||
@table @code
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12240,6 +12242,58 @@ which may be insufficient for some operations.
 | 
			
		|||
The file name of the qcow2 image.
 | 
			
		||||
@end table
 | 
			
		||||
 | 
			
		||||
The default @command{run-vm.sh} script that is returned by an invokation of
 | 
			
		||||
@command{guix system vm} does not add a @command{-net user} flag by default.
 | 
			
		||||
To get network access from within the vm add the @code{(dhcp-client-service)}
 | 
			
		||||
to your system definition and start the VM using
 | 
			
		||||
@command{`guix system vm config.scm` -net user}.  An important caveat of using
 | 
			
		||||
@command{-net user} for networking is that @command{ping} will not work, because
 | 
			
		||||
it uses the ICMP protocol.  You'll have to use a different command to check for
 | 
			
		||||
network connectivity, like for example @command{curl}.
 | 
			
		||||
 | 
			
		||||
@subsubsection Connecting Through SSH
 | 
			
		||||
 | 
			
		||||
To enable SSH inside a VM you need to add a SSH server like @code{(dropbear-service)}
 | 
			
		||||
or @code{(lsh-service)} to your VM.  The @code{(lsh-service}) doesn't currently
 | 
			
		||||
boot unsupervised.  It requires you to type some characters to initialize the
 | 
			
		||||
randomness generator.  In addition you need to forward the SSH port, 22 by
 | 
			
		||||
default, to the host.  You can do this with
 | 
			
		||||
 | 
			
		||||
@example
 | 
			
		||||
`guix system vm config.scm` -net user,hostfwd=tcp::10022-:22
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
To connect to the VM you can run
 | 
			
		||||
 | 
			
		||||
@example
 | 
			
		||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 10022
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
The @command{-p} tells @command{ssh} the port you want to connect to.
 | 
			
		||||
@command{-o UserKnownHostsFile=/dev/null} prevents @command{ssh} from complaining
 | 
			
		||||
every time you modify your @command{config.scm} file and the
 | 
			
		||||
@command{-o StrictHostKeyChecking=no} prevents you from having to allow a
 | 
			
		||||
connection to an unknown host every time you connect.
 | 
			
		||||
 | 
			
		||||
@subsubsection Using @command{virt-viewer} with Spice
 | 
			
		||||
 | 
			
		||||
As an alternative to the default @command{qemu} graphical client you can
 | 
			
		||||
use the @command{remote-viewer} from the @command{virt-viewer} package.  To
 | 
			
		||||
connect pass the @command{-spice port=5930,disable-ticketing} flag to
 | 
			
		||||
@command{qemu}.  See previous section for further information on how to do this.
 | 
			
		||||
 | 
			
		||||
Spice also allows you to do some nice stuff like share your clipboard with your
 | 
			
		||||
VM.  To enable that you'll also have to pass the following flags to @command{qemu}:
 | 
			
		||||
 | 
			
		||||
@example
 | 
			
		||||
-device virtio-serial-pci,id=virtio-serial0,max_ports=16,bus=pci.0,addr=0x5
 | 
			
		||||
-chardev spicevmc,name=vdagent,id=vdagent
 | 
			
		||||
-device virtserialport,nr=1,bus=virtio-serial0.0,chardev=vdagent,
 | 
			
		||||
name=com.redhat.spice.0
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
You'll also need to add the @pxref{Miscellaneous Services, Spice service}.
 | 
			
		||||
 | 
			
		||||
@node Defining Services
 | 
			
		||||
@subsection Defining Services
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -734,6 +734,7 @@ dist_patch_DATA =						\
 | 
			
		|||
  %D%/packages/patches/openjpeg-CVE-2016-5157.patch		\
 | 
			
		||||
  %D%/packages/patches/openjpeg-CVE-2016-7163.patch		\
 | 
			
		||||
  %D%/packages/patches/openjpeg-use-after-free-fix.patch	\
 | 
			
		||||
  %D%/packages/patches/openocd-nrf52.patch			\
 | 
			
		||||
  %D%/packages/patches/openssh-memory-exhaustion.patch		\
 | 
			
		||||
  %D%/packages/patches/openssl-runpath.patch			\
 | 
			
		||||
  %D%/packages/patches/openssl-1.1.0-c-rehash-in.patch		\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -406,13 +406,13 @@ detection, and lossless compression.")
 | 
			
		|||
(define-public borg
 | 
			
		||||
  (package
 | 
			
		||||
    (name "borg")
 | 
			
		||||
    (version "1.0.7")
 | 
			
		||||
    (version "1.0.8")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (pypi-uri "borgbackup" version))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "1l9iw55w5x51yxl3q89cf6avg80lajxvc8qz584hrsmnk6i56cr0"))
 | 
			
		||||
                "1fdfi0yzzdrrlml6780n4fh61sqm7pw6fcd1y67kfkvw8hy5c0k9"))
 | 
			
		||||
              (modules '((guix build utils)))
 | 
			
		||||
              (snippet
 | 
			
		||||
               '(for-each
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@
 | 
			
		|||
(define-public ccache
 | 
			
		||||
  (package
 | 
			
		||||
    (name "ccache")
 | 
			
		||||
    (version "3.3.2")
 | 
			
		||||
    (version "3.3.3")
 | 
			
		||||
    (source
 | 
			
		||||
     (origin
 | 
			
		||||
      (method url-fetch)
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
                          version ".tar.xz"))
 | 
			
		||||
      (sha256
 | 
			
		||||
       (base32
 | 
			
		||||
        "0c25l78hi36682l9cyxca78i8sdkmgmv9afip1s21y6q4g5qaxlh"))))
 | 
			
		||||
        "1v04ky2mhvx8gnqfbs9x2vvf4i9mzph4fwdg72s9xyhwv92sf0iv"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (native-inputs `(("perl" ,perl)     ;for test.sh
 | 
			
		||||
                     ("which" ,(@ (gnu packages base) which))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -320,14 +320,14 @@ device-specific programs to convert and print many types of files.")
 | 
			
		|||
(define-public hplip
 | 
			
		||||
  (package
 | 
			
		||||
    (name "hplip")
 | 
			
		||||
    (version "3.16.8")
 | 
			
		||||
    (version "3.16.10")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append "mirror://sourceforge/hplip/hplip/" version
 | 
			
		||||
                                  "/hplip-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "1svcalf2nc7mvxndp9zz3xp43w66z45rrsr5syl8fx61a6p6gnm9"))))
 | 
			
		||||
                "117f1p0splg51ljn4nn97c0mbl0jba440ahb3d8njq7p6h1lxd25"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (home-page "http://hplipopensource.com/")
 | 
			
		||||
    (synopsis "HP Printer Drivers")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 | 
			
		||||
;;; Copyright © 2016 John Darrington <jmd@gnu.org>
 | 
			
		||||
;;; Copyright © 2016 ng0 <ng0@we.make.ritual.n0.is>
 | 
			
		||||
;;; Copyright © 2016 Tobias Geerinckx-Rice <me@tobias.gr>
 | 
			
		||||
;;;
 | 
			
		||||
;;; This file is part of GNU Guix.
 | 
			
		||||
;;;
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,7 @@
 | 
			
		|||
 | 
			
		||||
(define-module (gnu packages dns)
 | 
			
		||||
  #:use-module (gnu packages autotools)
 | 
			
		||||
  #:use-module (gnu packages base)
 | 
			
		||||
  #:use-module (gnu packages databases)
 | 
			
		||||
  #:use-module (gnu packages groff)
 | 
			
		||||
  #:use-module (gnu packages linux)
 | 
			
		||||
| 
						 | 
				
			
			@ -161,3 +163,40 @@ asynchronous fashion.")
 | 
			
		|||
                   license:bsd-3
 | 
			
		||||
                   (license:non-copyleft "file://LICENSE") ; includes.h
 | 
			
		||||
                   license:openssl))))
 | 
			
		||||
 | 
			
		||||
(define-public yadifa
 | 
			
		||||
  (package
 | 
			
		||||
    (name "yadifa")
 | 
			
		||||
    (version "2.2.1-6281")
 | 
			
		||||
    (source
 | 
			
		||||
     (origin
 | 
			
		||||
       (method url-fetch)
 | 
			
		||||
       (uri (string-append "http://cdn.yadifa.eu/sites/default/files/releases/"
 | 
			
		||||
                           name "-" version ".tar.gz"))
 | 
			
		||||
       (sha256
 | 
			
		||||
        (base32
 | 
			
		||||
         "0vj71z7i9lfbnp93k28aplwldp5mfli0kvrbwmha6fjha6kcr910"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("which" ,which)))
 | 
			
		||||
    (inputs
 | 
			
		||||
     `(("openssl" ,openssl)))
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:phases (modify-phases %standard-phases
 | 
			
		||||
                  (add-before 'configure 'omit-example-configurations
 | 
			
		||||
                              (lambda _ (substitute* "Makefile.in"
 | 
			
		||||
                                          ((" (etc|var)") "")))))
 | 
			
		||||
       #:configure-flags (list "--sysconfdir=/etc"      "--localstatedir=/var"
 | 
			
		||||
                               "--enable-shared"        "--disable-static"
 | 
			
		||||
                               "--enable-messages"      "--enable-ctrl"
 | 
			
		||||
                               ;; NSID is a rarely-used debugging aid, that also
 | 
			
		||||
                               ;; causes the build to fail. Just disable it.
 | 
			
		||||
                               "--disable-nsid")))
 | 
			
		||||
    (home-page "http://www.yadifa.eu/")
 | 
			
		||||
    (synopsis "Authoritative DNS name server")
 | 
			
		||||
    (description "YADIFA is an authorative name server for the Domain Name
 | 
			
		||||
System (DNS).  It aims for both higher performance and a smaller memory
 | 
			
		||||
footprint than other implementations, while remaining fully RFC-compliant.
 | 
			
		||||
YADIFA supports dynamic record updates and the Domain Name System Security
 | 
			
		||||
Extensions (DNSSEC).")
 | 
			
		||||
    (license license:bsd-3)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
;;; GNU Guix --- Functional package management for GNU
 | 
			
		||||
;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
 | 
			
		||||
;;; Copyright © 2016 Theodoros Foradis <theodoros.for@openmailbox.org>
 | 
			
		||||
;;; Copyright © 2016 David Craven <david@craven.ch>
 | 
			
		||||
;;;
 | 
			
		||||
;;; This file is part of GNU Guix.
 | 
			
		||||
;;;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,10 +29,15 @@
 | 
			
		|||
  #:use-module (guix build-system trivial)
 | 
			
		||||
  #:use-module (guix build utils)
 | 
			
		||||
  #:use-module (gnu packages)
 | 
			
		||||
  #:use-module (gnu packages autotools)
 | 
			
		||||
  #:use-module (gnu packages cross-base)
 | 
			
		||||
  #:use-module (gnu packages flex)
 | 
			
		||||
  #:use-module (gnu packages gcc)
 | 
			
		||||
  #:use-module (gnu packages gdb)
 | 
			
		||||
  #:use-module (gnu packages libftdi)
 | 
			
		||||
  #:use-module (gnu packages libusb)
 | 
			
		||||
  #:use-module (gnu packages perl)
 | 
			
		||||
  #:use-module (gnu packages pkg-config)
 | 
			
		||||
  #:use-module (gnu packages texinfo))
 | 
			
		||||
 | 
			
		||||
;; We must not use the released GCC sources here, because the cross-compiler
 | 
			
		||||
| 
						 | 
				
			
			@ -223,3 +229,136 @@ languages are C and C++.")
 | 
			
		|||
(define-public arm-none-eabi-nano-toolchain-6
 | 
			
		||||
  (arm-none-eabi-toolchain gcc-arm-none-eabi-6
 | 
			
		||||
                           newlib-nano-arm-none-eabi))
 | 
			
		||||
 | 
			
		||||
(define-public gdb-arm-none-eabi
 | 
			
		||||
  (package
 | 
			
		||||
    (inherit gdb)
 | 
			
		||||
    (name "gdb-arm-none-eabi")
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:configure-flags '("--target=arm-none-eabi"
 | 
			
		||||
                           "--enable-multilib"
 | 
			
		||||
                           "--enable-interwork"
 | 
			
		||||
                           "--enable-languages=c,c++"
 | 
			
		||||
                           "--disable-nls")
 | 
			
		||||
     ,@(package-arguments gdb)))))
 | 
			
		||||
 | 
			
		||||
(define-public libjaylink
 | 
			
		||||
  ;; No release tarballs available.
 | 
			
		||||
  (let ((commit "faa2a433fdd3de211728f3da5921133214af9dd3")
 | 
			
		||||
        (revision "1"))
 | 
			
		||||
    (package
 | 
			
		||||
      (name "libjaylink")
 | 
			
		||||
      (version (string-append "0.1.0-" revision "."
 | 
			
		||||
                              (string-take commit 7)))
 | 
			
		||||
      (source (origin
 | 
			
		||||
                (method git-fetch)
 | 
			
		||||
                (uri (git-reference
 | 
			
		||||
                      (url "git://git.zapb.de/libjaylink.git")
 | 
			
		||||
                      (commit commit)))
 | 
			
		||||
                (file-name (string-append name "-" version "-checkout"))
 | 
			
		||||
                (sha256
 | 
			
		||||
                 (base32
 | 
			
		||||
                  "02crr56csz8whq3q4mrmdzzgwp5b0qvxm0fb18drclc3zj44yxl2"))))
 | 
			
		||||
      (build-system gnu-build-system)
 | 
			
		||||
      (native-inputs
 | 
			
		||||
       `(("autoconf" ,autoconf)
 | 
			
		||||
         ("automake" ,automake)
 | 
			
		||||
         ("libtool" ,libtool)
 | 
			
		||||
         ("pkg-config" ,pkg-config)))
 | 
			
		||||
      (inputs
 | 
			
		||||
       `(("libusb" ,libusb)))
 | 
			
		||||
      (arguments
 | 
			
		||||
       `(#:phases
 | 
			
		||||
         (modify-phases %standard-phases
 | 
			
		||||
           (add-before 'configure 'autoreconf
 | 
			
		||||
             (lambda _
 | 
			
		||||
               (zero? (system* "autoreconf" "-vfi")))))))
 | 
			
		||||
      (home-page "http://repo.or.cz/w/libjaylink.git")
 | 
			
		||||
      (synopsis "Library to interface Segger J-Link devices")
 | 
			
		||||
      (description "libjaylink is a shared library written in C to access
 | 
			
		||||
SEGGER J-Link and compatible devices.")
 | 
			
		||||
      (license license:gpl2+))))
 | 
			
		||||
 | 
			
		||||
(define-public jimtcl
 | 
			
		||||
  (package
 | 
			
		||||
    (name "jimtcl")
 | 
			
		||||
    (version "0.77")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append
 | 
			
		||||
                    "https://github.com/msteveb/jimtcl"
 | 
			
		||||
                    "/archive/" version ".tar.gz"))
 | 
			
		||||
              (file-name (string-append name "-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "1cmk3qscqckg70chjyimzxa2qcka4qac0j4wq908kiijp45cax08"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         ;; Doesn't use autoconf.
 | 
			
		||||
         (replace 'configure
 | 
			
		||||
           (lambda* (#:key outputs #:allow-other-keys)
 | 
			
		||||
             (let ((out (assoc-ref outputs "out")))
 | 
			
		||||
               (zero? (system* "./configure"
 | 
			
		||||
                               (string-append "--prefix=" out)))))))))
 | 
			
		||||
    (home-page "http://jim.tcl.tk")
 | 
			
		||||
    (synopsis "Small footprint Tcl implementation")
 | 
			
		||||
    (description "Jim is a small footprint implementation of the Tcl programming
 | 
			
		||||
language.")
 | 
			
		||||
    (license license:bsd-2)))
 | 
			
		||||
 | 
			
		||||
(define-public openocd
 | 
			
		||||
  ;; FIXME: Use tarball release after nrf52 patch is merged.
 | 
			
		||||
  (let ((commit "674141e8a7a6413cb803d90c2a20150260015f81")
 | 
			
		||||
        (revision "1"))
 | 
			
		||||
    (package
 | 
			
		||||
      (name "openocd")
 | 
			
		||||
      (version (string-append "0.9.0-" revision "."
 | 
			
		||||
                              (string-take commit 7)))
 | 
			
		||||
      (source (origin
 | 
			
		||||
                (method git-fetch)
 | 
			
		||||
                (uri (git-reference
 | 
			
		||||
                      (url "git://git.code.sf.net/p/openocd/code.git")
 | 
			
		||||
                      (commit commit)))
 | 
			
		||||
                (sha256
 | 
			
		||||
                 (base32
 | 
			
		||||
                  "1i86jp0wawq78d73z8hp7q1pn7lmlvhjjr19f7299h4w40a5jf8j"))
 | 
			
		||||
                (file-name (string-append name "-" version "-checkout"))
 | 
			
		||||
                (patches
 | 
			
		||||
                 (search-patches "openocd-nrf52.patch"))))
 | 
			
		||||
      (build-system gnu-build-system)
 | 
			
		||||
      (native-inputs
 | 
			
		||||
       `(("autoconf" ,autoconf)
 | 
			
		||||
         ("automake" ,automake)
 | 
			
		||||
         ("libtool" ,libtool)
 | 
			
		||||
         ("pkg-config" ,pkg-config)))
 | 
			
		||||
      (inputs
 | 
			
		||||
       `(("hidapi" ,hidapi)
 | 
			
		||||
         ("jimtcl" ,jimtcl)
 | 
			
		||||
         ("libftdi" ,libftdi)
 | 
			
		||||
         ("libjaylink" ,libjaylink)
 | 
			
		||||
         ("libusb-compat" ,libusb-compat)))
 | 
			
		||||
      (arguments
 | 
			
		||||
       '(#:configure-flags
 | 
			
		||||
         (append (list "--disable-werror"
 | 
			
		||||
                       "--disable-internal-jimtcl"
 | 
			
		||||
                       "--disable-internal-libjaylink")
 | 
			
		||||
                 (map (lambda (programmer)
 | 
			
		||||
                        (string-append "--enable-" programmer))
 | 
			
		||||
                      '("amtjtagaccel" "armjtagew" "buspirate" "ftdi"
 | 
			
		||||
                        "gw16012" "jlink" "oocd_trace" "opendous" "osbdm"
 | 
			
		||||
                        "parport" "aice" "cmsis-dap" "dummy" "jtag_vpi"
 | 
			
		||||
                        "remote-bitbang" "rlink" "stlink" "ti-icdi" "ulink"
 | 
			
		||||
                        "usbprog" "vsllink" "usb-blaster-2" "usb_blaster"
 | 
			
		||||
                        "presto" "openjtag")))
 | 
			
		||||
         #:phases
 | 
			
		||||
         (modify-phases %standard-phases
 | 
			
		||||
           (add-before 'configure 'autoreconf
 | 
			
		||||
             (lambda _
 | 
			
		||||
               (zero? (system* "autoreconf" "-vfi")))))))
 | 
			
		||||
      (home-page "http://openocd.org")
 | 
			
		||||
      (synopsis "On-Chip Debugger")
 | 
			
		||||
      (description "OpenOCD provides on-chip programming and debugging support
 | 
			
		||||
with a layered architecture of JTAG interface and TAP support.")
 | 
			
		||||
      (license license:gpl2))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,3 +79,22 @@ regular expressions for each rule.  Whenever it finds a match, it
 | 
			
		|||
executes the corresponding C code.")
 | 
			
		||||
    (license (non-copyleft "file://COPYING"
 | 
			
		||||
                        "See COPYING in the distribution."))))
 | 
			
		||||
 | 
			
		||||
(define-public flex-2.6.1
 | 
			
		||||
  ;; The kservice and solid packages use flex.  extra-cmake-modules
 | 
			
		||||
  ;; forces C89 for all C files for compatibility with windows.
 | 
			
		||||
  ;; Flex 2.6.0 generates a lexer containing a single line comment.  Single
 | 
			
		||||
  ;; line comments are part of the C99 standard, so the lexer won't compile
 | 
			
		||||
  ;; if C89 is used.
 | 
			
		||||
  (package
 | 
			
		||||
    (inherit flex)
 | 
			
		||||
    (version "2.6.1")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append
 | 
			
		||||
                    "https://github.com/westes/flex"
 | 
			
		||||
                    "/releases/download/v" version "/"
 | 
			
		||||
                    "flex-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "0fy14c35yz2m1n1m4f02by3501fn0cca37zn7jp8lpp4b3kgjhrw"))))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -329,7 +329,7 @@ asynchronously and at a user-defined speed.")
 | 
			
		|||
(define-public chess
 | 
			
		||||
  (package
 | 
			
		||||
    (name "chess")
 | 
			
		||||
    (version "6.2.3")
 | 
			
		||||
    (version "6.2.4")
 | 
			
		||||
    (source
 | 
			
		||||
     (origin
 | 
			
		||||
       (method url-fetch)
 | 
			
		||||
| 
						 | 
				
			
			@ -337,9 +337,9 @@ asynchronously and at a user-defined speed.")
 | 
			
		|||
                           ".tar.gz"))
 | 
			
		||||
       (sha256
 | 
			
		||||
        (base32
 | 
			
		||||
         "10hvnfhj9bkpz80x20jgxyqvgvrcgfdp8sfcbcrf1dgjn9v936bq"))))
 | 
			
		||||
         "1vw2w3jwnmn44d5vsw47f8y70xvxcsz9m5msq9fgqlzjch15qhiw"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (home-page "http://www.gnu.org/software/chess")
 | 
			
		||||
    (home-page "https://www.gnu.org/software/chess")
 | 
			
		||||
    (synopsis "Full chess implementation")
 | 
			
		||||
    (description "GNU Chess is a chess engine.  It allows you to compete
 | 
			
		||||
against the computer in a game of chess, either through the default terminal
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -410,7 +410,8 @@ standards.")
 | 
			
		|||
       ("glib" ,glib)
 | 
			
		||||
       ("gstreamer" ,gstreamer)
 | 
			
		||||
       ("gst-plugins-base" ,gst-plugins-base)
 | 
			
		||||
       ("gtk+" ,gtk+-2)
 | 
			
		||||
       ("gtk+" ,gtk+)
 | 
			
		||||
       ("gtk+-2" ,gtk+-2)
 | 
			
		||||
       ("pango" ,pango)
 | 
			
		||||
       ("freetype" ,freetype)
 | 
			
		||||
       ("hunspell" ,hunspell)
 | 
			
		||||
| 
						 | 
				
			
			@ -454,7 +455,7 @@ standards.")
 | 
			
		|||
       ;; practice somehow.  See <http://hydra.gnu.org/build/378133>.
 | 
			
		||||
       #:validate-runpath? #f
 | 
			
		||||
 | 
			
		||||
       #:configure-flags '("--enable-default-toolkit=cairo-gtk2"
 | 
			
		||||
       #:configure-flags '("--enable-default-toolkit=cairo-gtk3"
 | 
			
		||||
                           "--enable-pango"
 | 
			
		||||
                           "--enable-gio"
 | 
			
		||||
                           "--enable-svg"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
;;; Copyright © 2015 Andy Wingo <wingo@igalia.com>
 | 
			
		||||
;;; Copyright © 2015, 2016 Ricardo Wurmus <rekado@elephly.net>
 | 
			
		||||
;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il>
 | 
			
		||||
;;; Copyright © 2016 Theodoros Foradis <theodoros.for@openmailbox.org>
 | 
			
		||||
;;;
 | 
			
		||||
;;; This file is part of GNU Guix.
 | 
			
		||||
;;;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +30,7 @@
 | 
			
		|||
  #:use-module (guix build-system gnu)
 | 
			
		||||
  #:use-module (guix build-system glib-or-gtk)
 | 
			
		||||
  #:use-module (guix build-system python)
 | 
			
		||||
  #:use-module (gnu packages autotools)
 | 
			
		||||
  #:use-module (gnu packages gnupg)
 | 
			
		||||
  #:use-module (gnu packages gtk)
 | 
			
		||||
  #:use-module (gnu packages linux)
 | 
			
		||||
| 
						 | 
				
			
			@ -201,3 +203,39 @@ proposed for standardization.")
 | 
			
		|||
  (MTP), which allows media files to be transferred to and from many portable
 | 
			
		||||
devices.")
 | 
			
		||||
    (license bsd-3)))
 | 
			
		||||
 | 
			
		||||
(define-public hidapi
 | 
			
		||||
  (package
 | 
			
		||||
    (name "hidapi")
 | 
			
		||||
    (version "0.8.0-rc1")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append "https://github.com/signal11/hidapi/archive/hidapi-"
 | 
			
		||||
                                  version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "0qdgyj9rgb7n0nk3ghfswrhzzknxqn4ibn3wj8g4r828pw07451w"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     '(#:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         (add-before 'configure 'bootstrap
 | 
			
		||||
           (lambda _
 | 
			
		||||
             (zero? (system* "autoreconf" "-vfi")))))))
 | 
			
		||||
    (inputs
 | 
			
		||||
     `(("libusb" ,libusb)
 | 
			
		||||
       ("udev" ,eudev)))
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("autoconf" ,autoconf)
 | 
			
		||||
       ("automake" ,automake)
 | 
			
		||||
       ("libtool" ,libtool)
 | 
			
		||||
       ("pkg-config" ,pkg-config)))
 | 
			
		||||
    (home-page "http://www.signal11.us/oss/hidapi/")
 | 
			
		||||
    (synopsis "HID API library")
 | 
			
		||||
    (description
 | 
			
		||||
     "HIDAPI is a library which allows an application to interface with USB and Bluetooth
 | 
			
		||||
HID-Class devices.")
 | 
			
		||||
    ;; HIDAPI can be used under one of three licenses.
 | 
			
		||||
    (license (list gpl3
 | 
			
		||||
                   bsd-3
 | 
			
		||||
                   non-copyleft "file://LICENSE-orig.txt"))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,6 +71,8 @@
 | 
			
		|||
  #:use-module (gnu packages texinfo)
 | 
			
		||||
  #:use-module (gnu packages tls)
 | 
			
		||||
  #:use-module (gnu packages xml)
 | 
			
		||||
  #:use-module (gnu packages xdisorg)
 | 
			
		||||
  #:use-module (gnu packages xorg)
 | 
			
		||||
  #:use-module (guix build-system cmake)
 | 
			
		||||
  #:use-module (guix build-system gnu)
 | 
			
		||||
  #:use-module (guix build-system python)
 | 
			
		||||
| 
						 | 
				
			
			@ -323,14 +325,14 @@ It has been modified to remove all non-free binary blobs.")
 | 
			
		|||
(define %intel-compatible-systems '("x86_64-linux" "i686-linux"))
 | 
			
		||||
 | 
			
		||||
(define-public linux-libre
 | 
			
		||||
  (make-linux-libre "4.8.4"
 | 
			
		||||
                    "06fb2b1y7w0ixq4savn3hddp326mmzmg3400dpr8lyg919bwck3x"
 | 
			
		||||
  (make-linux-libre "4.8.5"
 | 
			
		||||
                    "124sf2jvckn0afy1zfyaqgr1679qsx3fnylw1wpl7p5298hwyf9m"
 | 
			
		||||
                    %intel-compatible-systems
 | 
			
		||||
                    #:configuration-file kernel-config))
 | 
			
		||||
 | 
			
		||||
(define-public linux-libre-4.4
 | 
			
		||||
  (make-linux-libre "4.4.27"
 | 
			
		||||
                    "07g0y8zbspw8d65386llcsnqlbv2s24dxvvbwm9kwm87rk3vin1r"
 | 
			
		||||
  (make-linux-libre "4.4.28"
 | 
			
		||||
                    "1yn74vci0bygn5bi9mcgx1zz8xw9m3jb6j260wqsgkv1hbksa2yp"
 | 
			
		||||
                    %intel-compatible-systems
 | 
			
		||||
                    #:configuration-file kernel-config))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -341,8 +343,8 @@ It has been modified to remove all non-free binary blobs.")
 | 
			
		|||
                    #:configuration-file kernel-config))
 | 
			
		||||
 | 
			
		||||
;; Avoid rebuilding kernel variants when there is a minor version bump.
 | 
			
		||||
(define %linux-libre-version "4.8.4")
 | 
			
		||||
(define %linux-libre-hash "06fb2b1y7w0ixq4savn3hddp326mmzmg3400dpr8lyg919bwck3x")
 | 
			
		||||
(define %linux-libre-version "4.8.5")
 | 
			
		||||
(define %linux-libre-hash "124sf2jvckn0afy1zfyaqgr1679qsx3fnylw1wpl7p5298hwyf9m")
 | 
			
		||||
 | 
			
		||||
(define-public linux-libre-arm-generic
 | 
			
		||||
  (make-linux-libre %linux-libre-version
 | 
			
		||||
| 
						 | 
				
			
			@ -3095,3 +3097,44 @@ interface that should be familiar to, and easily adopted by, application
 | 
			
		|||
developers.")
 | 
			
		||||
    (home-page "https://github.com/seccomp/libseccomp")
 | 
			
		||||
    (license license:lgpl2.1)))
 | 
			
		||||
 | 
			
		||||
(define-public radeontop
 | 
			
		||||
  (package
 | 
			
		||||
    (name "radeontop")
 | 
			
		||||
    (version "0.9")
 | 
			
		||||
    (home-page "https://github.com/clbr/radeontop/")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append home-page "/archive/v" version ".tar.gz"))
 | 
			
		||||
              (file-name (string-append name "-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "07fnimn6wwablmdjw0av11hk9a6xilbryh09izq4b2ic4b8md2p7"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:phases (modify-phases %standard-phases
 | 
			
		||||
                  ;; getver.sh uses ‘git --describe’, isn't worth an extra git
 | 
			
		||||
                  ;; dependency, and doesn't even work on release(!) tarballs.
 | 
			
		||||
                  (add-after 'unpack 'report-correct-version
 | 
			
		||||
                    (lambda _ (substitute* "getver.sh"
 | 
			
		||||
                                (("ver=unknown")
 | 
			
		||||
                                 (string-append "ver=" ,version)))))
 | 
			
		||||
                  (delete 'configure))  ; no configure script
 | 
			
		||||
       #:make-flags (list "CC=gcc"
 | 
			
		||||
                          (string-append "PREFIX=" %output))
 | 
			
		||||
       #:tests? #f))                    ; no tests
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("gnu-gettext" ,gnu-gettext)
 | 
			
		||||
       ("pkg-config" ,pkg-config)))
 | 
			
		||||
    (inputs
 | 
			
		||||
     `(("libdrm" ,libdrm)
 | 
			
		||||
       ("libpciaccess" ,libpciaccess)
 | 
			
		||||
       ("ncurses" ,ncurses)))
 | 
			
		||||
    (synopsis "Usage monitor for AMD Radeon graphics")
 | 
			
		||||
    (description "RadeonTop monitors resource consumption on supported AMD
 | 
			
		||||
Radeon Graphics Processing Units (GPUs), either in real time as bar graphs on
 | 
			
		||||
a terminal or saved to a file for further processing.  It measures both the
 | 
			
		||||
activity of the GPU as a whole, which is also accurate during OpenCL
 | 
			
		||||
computations, as well as separate component statistics that are only meaningful
 | 
			
		||||
under OpenGL graphics workloads.")
 | 
			
		||||
    (license license:gpl3)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -311,7 +311,7 @@ and corrections.  It is based on a Bayesian filter.")
 | 
			
		|||
(define-public offlineimap
 | 
			
		||||
  (package
 | 
			
		||||
    (name "offlineimap")
 | 
			
		||||
    (version "7.0.8")
 | 
			
		||||
    (version "7.0.9")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append "https://github.com/OfflineIMAP/offlineimap/"
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +319,7 @@ and corrections.  It is based on a Bayesian filter.")
 | 
			
		|||
              (file-name (string-append name "-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "0smxh5ag3cbn92kp49jq950j5m2pivs9kr04prpd1lw62hy7gnhr"))))
 | 
			
		||||
                "04kapx0ddz7ccwhcjshkml2y916wcan3rl28mpmq25p4gywlkhxf"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("asciidoc" ,asciidoc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1225,7 +1225,7 @@ arising after the discretization of partial differential equations.")
 | 
			
		|||
(define-public mumps
 | 
			
		||||
  (package
 | 
			
		||||
    (name "mumps")
 | 
			
		||||
    (version "5.0.1")
 | 
			
		||||
    (version "5.0.2")
 | 
			
		||||
    (source
 | 
			
		||||
     (origin
 | 
			
		||||
       (method url-fetch)
 | 
			
		||||
| 
						 | 
				
			
			@ -1233,7 +1233,7 @@ arising after the discretization of partial differential equations.")
 | 
			
		|||
                           version ".tar.gz"))
 | 
			
		||||
       (sha256
 | 
			
		||||
        (base32
 | 
			
		||||
         "1820jfp3mbl7n85765v5mp6p0gzqpgr4d2lrnhwj4gl7cwp5ndah"))
 | 
			
		||||
         "0igyc1pfzxdhpbad3v3lb86ixkdbqa1a8gbs15b04r2294h2nabp"))
 | 
			
		||||
       (patches (search-patches "mumps-build-parallelism.patch"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (inputs
 | 
			
		||||
| 
						 | 
				
			
			@ -1250,8 +1250,7 @@ arising after the discretization of partial differential equations.")
 | 
			
		|||
                  ,@%gnu-build-system-modules)
 | 
			
		||||
       #:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         (replace
 | 
			
		||||
          'configure
 | 
			
		||||
         (replace 'configure
 | 
			
		||||
          (lambda* (#:key inputs #:allow-other-keys)
 | 
			
		||||
            (call-with-output-file "Makefile.inc"
 | 
			
		||||
              (lambda (port)
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,15 +1311,13 @@ IORDERINGSC  = $(IPORD) $(IMETIS) $(ISCOTCH)"
 | 
			
		|||
                           `((,ptscotch
 | 
			
		||||
                              "-lptesmumps -lptscotch -lptscotcherr "
 | 
			
		||||
                              "-Dptscotch")))))))))
 | 
			
		||||
         (replace
 | 
			
		||||
          'build
 | 
			
		||||
         (replace 'build
 | 
			
		||||
          ;; By default only the d-precision library is built.  Make with "all"
 | 
			
		||||
          ;; target so that all precision libraries and examples are built.
 | 
			
		||||
          (lambda _
 | 
			
		||||
            (zero? (system* "make" "all"
 | 
			
		||||
                            (format #f "-j~a" (parallel-job-count))))))
 | 
			
		||||
         (replace
 | 
			
		||||
          'check
 | 
			
		||||
         (replace 'check
 | 
			
		||||
          ;; Run the simple test drivers, which read test input from stdin:
 | 
			
		||||
          ;; from the "real" input for the single- and double-precision
 | 
			
		||||
          ;; testers, and from the "cmplx" input for complex-precision
 | 
			
		||||
| 
						 | 
				
			
			@ -1343,15 +1340,15 @@ IORDERINGSC  = $(IPORD) $(IMETIS) $(ISCOTCH)"
 | 
			
		|||
                     (zero? (close-pipe tester)))))
 | 
			
		||||
               '("s" "d" "c" "z")
 | 
			
		||||
               '("real" "real" "cmplx" "cmplx")))))
 | 
			
		||||
         (replace
 | 
			
		||||
          'install
 | 
			
		||||
          (lambda* (#:key outputs #:allow-other-keys)
 | 
			
		||||
            (let ((out (assoc-ref outputs "out")))
 | 
			
		||||
              (copy-recursively "lib" (string-append out "/lib"))
 | 
			
		||||
              (copy-recursively "include" (string-append out "/include"))
 | 
			
		||||
              (when (file-exists? "libseq/libmpiseq.a")
 | 
			
		||||
                (copy-file "libseq/libmpiseq.a"
 | 
			
		||||
                           (string-append out "/lib/libmpiseq.a")))))))))
 | 
			
		||||
         (replace 'install
 | 
			
		||||
           (lambda* (#:key outputs #:allow-other-keys)
 | 
			
		||||
             (let* ((out (assoc-ref outputs "out"))
 | 
			
		||||
                    (libdir (string-append out "/lib")))
 | 
			
		||||
               (copy-recursively "lib" libdir)
 | 
			
		||||
               (copy-recursively "include" (string-append out "/include"))
 | 
			
		||||
               (when (file-exists? "libseq/libmpiseq.a")
 | 
			
		||||
                 (install-file "libseq/libmpiseq.a" libdir))
 | 
			
		||||
               #t))))))
 | 
			
		||||
    (home-page "http://mumps.enseeiht.fr")
 | 
			
		||||
    (synopsis "Multifrontal sparse direct solver")
 | 
			
		||||
    (description
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1772,9 +1772,9 @@ MusicBrainz database.")
 | 
			
		|||
(define-public python2-musicbrainzngs
 | 
			
		||||
  (package-with-python2 python-musicbrainzngs))
 | 
			
		||||
 | 
			
		||||
(define-public python-pyechonest
 | 
			
		||||
(define-public python2-pyechonest
 | 
			
		||||
  (package
 | 
			
		||||
    (name "python-pyechonest")
 | 
			
		||||
    (name "python2-pyechonest")
 | 
			
		||||
    (version "9.0.0")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
| 
						 | 
				
			
			@ -1783,6 +1783,11 @@ MusicBrainz database.")
 | 
			
		|||
               (base32
 | 
			
		||||
                "1584nira3rkiman9dm81kdshihmkj21s8navndz2l8spnjwb790x"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(;; Python 3 is not supported:
 | 
			
		||||
       ;; https://github.com/echonest/pyechonest/issues/42
 | 
			
		||||
       #:python ,python-2))
 | 
			
		||||
    (native-inputs `(("python2-setuptools" ,python2-setuptools)))
 | 
			
		||||
    (home-page "https://github.com/echonest/pyechonest")
 | 
			
		||||
    (synopsis "Python interface to The Echo Nest APIs")
 | 
			
		||||
    (description "Pyechonest is a Python library for the Echo Nest API.  With
 | 
			
		||||
| 
						 | 
				
			
			@ -1799,13 +1804,7 @@ hotttnesss, audio_summary, or tracks.
 | 
			
		|||
about the track including key, duration, mode, tempo, time signature along with
 | 
			
		||||
detailed track info including timbre, pitch, rhythm and loudness information.
 | 
			
		||||
@end enumerate\n")
 | 
			
		||||
    (license license:bsd-3)
 | 
			
		||||
    (properties `((python2-variant . ,(delay python2-pyechonest))))))
 | 
			
		||||
 | 
			
		||||
(define-public python2-pyechonest
 | 
			
		||||
  (package (inherit (package-with-python2
 | 
			
		||||
                     (strip-python2-variant python-pyechonest)))
 | 
			
		||||
    (native-inputs `(("python2-setuptools" ,python2-setuptools)))))
 | 
			
		||||
    (license license:bsd-3)))
 | 
			
		||||
 | 
			
		||||
(define-public python-pylast
 | 
			
		||||
  (package
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										843
									
								
								gnu/packages/patches/openocd-nrf52.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										843
									
								
								gnu/packages/patches/openocd-nrf52.patch
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,843 @@
 | 
			
		|||
This patch adds support for nRF52 series devices.  It is patchset 7 from
 | 
			
		||||
<http://openocd.zylin.com/#/c/3511/>, which has been tested, but not
 | 
			
		||||
merged yet in master.
 | 
			
		||||
 | 
			
		||||
From: Michael Dietz <mjdietzx@gmail.com>
 | 
			
		||||
Date: Mon, 30 May 2016 12:50:44 +0000 (-0700)
 | 
			
		||||
Subject: Added support for nRF52 Series Devices.
 | 
			
		||||
X-Git-Url: http://openocd.zylin.com/gitweb?p=openocd.git;a=commitdiff_plain;h=9ba15633e221d9d72e320372ba8f49d3f30d4bce
 | 
			
		||||
 | 
			
		||||
Added support for nRF52 Series Devices.
 | 
			
		||||
 | 
			
		||||
Both nrf52.c and nrf52.cfg are based off of previous nRF51 files.
 | 
			
		||||
- Some possible race conditions with NVMC have been fixed in nRF52.c
 | 
			
		||||
- Removed nrf51_get_probed_chip_if_halted() as the core does not have to be halted to perform operations where it is called.
 | 
			
		||||
- Only registers that are needed by openOCD are defined, some registers in nRF51 don't exist in nRF52 and are removed.
 | 
			
		||||
- Some all around cleanup has been done.
 | 
			
		||||
- The protection mechanism is completely different on nRF52 and this has not been implemented yet - just prints a warning and returns for now.
 | 
			
		||||
 | 
			
		||||
Change-Id: I4dd42c86f33f450709bb981806c2655f04aa6201
 | 
			
		||||
Signed-off-by: Michael Dietz <mjdietzx@gmail.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
 | 
			
		||||
index c167e8f..b6a2be3 100644
 | 
			
		||||
--- a/src/flash/nor/Makefile.am
 | 
			
		||||
+++ b/src/flash/nor/Makefile.am
 | 
			
		||||
@@ -37,6 +37,7 @@ NOR_DRIVERS = \
 | 
			
		||||
 	niietcm4.c \
 | 
			
		||||
 	non_cfi.c \
 | 
			
		||||
 	nrf51.c \
 | 
			
		||||
+	nrf52.c \
 | 
			
		||||
 	numicro.c \
 | 
			
		||||
 	ocl.c \
 | 
			
		||||
 	pic32mx.c \
 | 
			
		||||
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
 | 
			
		||||
index 56a5cb2..3e071bd 100644
 | 
			
		||||
--- a/src/flash/nor/drivers.c
 | 
			
		||||
+++ b/src/flash/nor/drivers.c
 | 
			
		||||
@@ -48,6 +48,7 @@ extern struct flash_driver mdr_flash;
 | 
			
		||||
 extern struct flash_driver mrvlqspi_flash;
 | 
			
		||||
 extern struct flash_driver niietcm4_flash;
 | 
			
		||||
 extern struct flash_driver nrf51_flash;
 | 
			
		||||
+extern struct flash_driver nrf52_flash;
 | 
			
		||||
 extern struct flash_driver numicro_flash;
 | 
			
		||||
 extern struct flash_driver ocl_flash;
 | 
			
		||||
 extern struct flash_driver pic32mx_flash;
 | 
			
		||||
@@ -100,6 +101,7 @@ static struct flash_driver *flash_drivers[] = {
 | 
			
		||||
 	&mrvlqspi_flash,
 | 
			
		||||
 	&niietcm4_flash,
 | 
			
		||||
 	&nrf51_flash,
 | 
			
		||||
+	&nrf52_flash,
 | 
			
		||||
 	&numicro_flash,
 | 
			
		||||
 	&ocl_flash,
 | 
			
		||||
 	&pic32mx_flash,
 | 
			
		||||
diff --git a/src/flash/nor/nrf52.c b/src/flash/nor/nrf52.c
 | 
			
		||||
new file mode 100644
 | 
			
		||||
index 0000000..7f2bd35
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/src/flash/nor/nrf52.c
 | 
			
		||||
@@ -0,0 +1,733 @@
 | 
			
		||||
+/***************************************************************************
 | 
			
		||||
+ *   Copyright (C) 2013 Synapse Product Development                        *
 | 
			
		||||
+ *   Andrey Smirnov <andrew.smironv@gmail.com>                             *
 | 
			
		||||
+ *   Angus Gratton <gus@projectgus.com>                                    *
 | 
			
		||||
+ *   Erdem U. Altunyurt <spamjunkeater@gmail.com>                          *
 | 
			
		||||
+ *                                                                         *
 | 
			
		||||
+ *   This program is free software; you can redistribute it and/or modify  *
 | 
			
		||||
+ *   it under the terms of the GNU General Public License as published by  *
 | 
			
		||||
+ *   the Free Software Foundation; either version 2 of the License, or     *
 | 
			
		||||
+ *   (at your option) any later version.                                   *
 | 
			
		||||
+ *                                                                         *
 | 
			
		||||
+ *   This program is distributed in the hope that it will be useful,       *
 | 
			
		||||
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 | 
			
		||||
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 | 
			
		||||
+ *   GNU General Public License for more details.                          *
 | 
			
		||||
+ *                                                                         *
 | 
			
		||||
+ *   You should have received a copy of the GNU General Public License     *
 | 
			
		||||
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 | 
			
		||||
+ ***************************************************************************/
 | 
			
		||||
+
 | 
			
		||||
+#ifdef HAVE_CONFIG_H
 | 
			
		||||
+#include "config.h"
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#include <stdlib.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "imp.h"
 | 
			
		||||
+#include <target/algorithm.h>
 | 
			
		||||
+#include <target/armv7m.h>
 | 
			
		||||
+#include <helper/types.h>
 | 
			
		||||
+
 | 
			
		||||
+/* nRF52 Register addresses used by openOCD. */
 | 
			
		||||
+#define NRF52_FLASH_BASE_ADDR        (0x0)
 | 
			
		||||
+
 | 
			
		||||
+#define NRF52_FICR_BASE_ADDR         (0x10000000)
 | 
			
		||||
+#define NRF52_FICR_CODEPAGESIZE_ADDR (NRF52_FICR_BASE_ADDR | 0x010)
 | 
			
		||||
+#define NRF52_FICR_CODESIZE_ADDR     (NRF52_FICR_BASE_ADDR | 0x014)
 | 
			
		||||
+
 | 
			
		||||
+#define NRF52_UICR_BASE_ADDR         (0x10001000)
 | 
			
		||||
+
 | 
			
		||||
+#define NRF52_NVMC_BASE_ADDR         (0x4001E000)
 | 
			
		||||
+#define NRF52_NVMC_READY_ADDR        (NRF52_NVMC_BASE_ADDR | 0x400)
 | 
			
		||||
+#define NRF52_NVMC_CONFIG_ADDR       (NRF52_NVMC_BASE_ADDR | 0x504)
 | 
			
		||||
+#define NRF52_NVMC_ERASEPAGE_ADDR    (NRF52_NVMC_BASE_ADDR | 0x508)
 | 
			
		||||
+#define NRF52_NVMC_ERASEALL_ADDR     (NRF52_NVMC_BASE_ADDR | 0x50C)
 | 
			
		||||
+#define NRF52_NVMC_ERASEUICR_ADDR    (NRF52_NVMC_BASE_ADDR | 0x514)
 | 
			
		||||
+
 | 
			
		||||
+/* nRF52 bit fields. */
 | 
			
		||||
+enum nrf52_nvmc_config_bits {
 | 
			
		||||
+	NRF52_NVMC_CONFIG_REN = 0x0,
 | 
			
		||||
+	NRF52_NVMC_CONFIG_WEN = 0x01,
 | 
			
		||||
+	NRF52_NVMC_CONFIG_EEN = 0x02
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+enum nrf52_nvmc_ready_bits {
 | 
			
		||||
+	NRF52_NVMC_BUSY  = 0x0,
 | 
			
		||||
+	NRF52_NVMC_READY = 0x01
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+/* nRF52 state information. */
 | 
			
		||||
+struct nrf52_info {
 | 
			
		||||
+	uint32_t code_page_size; /* Size of FLASH page in bytes. */
 | 
			
		||||
+	uint32_t code_memory_size; /* Size of Code FLASH region in bytes. */
 | 
			
		||||
+
 | 
			
		||||
+	struct {
 | 
			
		||||
+		bool probed;
 | 
			
		||||
+		int (*write) (struct flash_bank *bank,
 | 
			
		||||
+				struct nrf52_info *chip,
 | 
			
		||||
+				const uint8_t *buffer, uint32_t offset, uint32_t count);
 | 
			
		||||
+	} bank[2]; /* There are two regions in nRF52 FLASH - Code and UICR. */
 | 
			
		||||
+	struct target *target;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_protect_check(struct flash_bank *bank);
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_probe(struct flash_bank *bank)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	res = target_read_u32(chip->target,
 | 
			
		||||
+						NRF52_FICR_CODEPAGESIZE_ADDR,
 | 
			
		||||
+						&chip->code_page_size);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Couldn't read code page size");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	res = target_read_u32(chip->target,
 | 
			
		||||
+						NRF52_FICR_CODESIZE_ADDR,
 | 
			
		||||
+						&chip->code_memory_size);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Couldn't read code memory size");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	chip->code_memory_size = chip->code_memory_size * chip->code_page_size;
 | 
			
		||||
+
 | 
			
		||||
+	if (bank->base == NRF52_FLASH_BASE_ADDR) {
 | 
			
		||||
+		bank->size = chip->code_memory_size;
 | 
			
		||||
+		bank->num_sectors = bank->size / chip->code_page_size;
 | 
			
		||||
+		bank->sectors = calloc(bank->num_sectors,
 | 
			
		||||
+							sizeof((bank->sectors)[0]));
 | 
			
		||||
+		if (!bank->sectors)
 | 
			
		||||
+			return ERROR_FLASH_BANK_NOT_PROBED;
 | 
			
		||||
+
 | 
			
		||||
+		/* Fill out the sector information: All nRF51 sectors are the same size. */
 | 
			
		||||
+		for (int i = 0; i < bank->num_sectors; i++) {
 | 
			
		||||
+			bank->sectors[i].size = chip->code_page_size;
 | 
			
		||||
+			bank->sectors[i].offset	= i * chip->code_page_size;
 | 
			
		||||
+
 | 
			
		||||
+			/* Mark as unknown. */
 | 
			
		||||
+			bank->sectors[i].is_erased = -1;
 | 
			
		||||
+			bank->sectors[i].is_protected = -1;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		nrf52_protect_check(bank);
 | 
			
		||||
+
 | 
			
		||||
+		chip->bank[0].probed = true;
 | 
			
		||||
+	} else { /* This is the UICR bank. */
 | 
			
		||||
+		bank->size = chip->code_page_size;
 | 
			
		||||
+		bank->num_sectors = 1;
 | 
			
		||||
+		bank->sectors = calloc(bank->num_sectors,
 | 
			
		||||
+							sizeof((bank->sectors)[0]));
 | 
			
		||||
+		if (!bank->sectors)
 | 
			
		||||
+			return ERROR_FLASH_BANK_NOT_PROBED;
 | 
			
		||||
+
 | 
			
		||||
+		bank->sectors[0].size = bank->size;
 | 
			
		||||
+		bank->sectors[0].offset	= 0;
 | 
			
		||||
+
 | 
			
		||||
+		bank->sectors[0].is_erased = -1;
 | 
			
		||||
+		bank->sectors[0].is_protected = -1;
 | 
			
		||||
+
 | 
			
		||||
+		chip->bank[1].probed = true;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_bank_is_probed(struct flash_bank *bank)
 | 
			
		||||
+{
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	return chip->bank[bank->bank_number].probed;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_auto_probe(struct flash_bank *bank)
 | 
			
		||||
+{
 | 
			
		||||
+	if (!nrf52_bank_is_probed(bank))
 | 
			
		||||
+		return nrf52_probe(bank);
 | 
			
		||||
+	else
 | 
			
		||||
+		return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_wait_for_nvmc(struct nrf52_info *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	uint32_t ready;
 | 
			
		||||
+	int timeout = 100;
 | 
			
		||||
+
 | 
			
		||||
+	do {
 | 
			
		||||
+		res = target_read_u32(chip->target, NRF52_NVMC_READY_ADDR, &ready);
 | 
			
		||||
+		if (res != ERROR_OK) {
 | 
			
		||||
+			LOG_ERROR("Couldn't read NVMC_READY register");
 | 
			
		||||
+			return res;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (ready == NRF52_NVMC_READY)
 | 
			
		||||
+			return ERROR_OK;
 | 
			
		||||
+
 | 
			
		||||
+		alive_sleep(1);
 | 
			
		||||
+	} while (timeout--);
 | 
			
		||||
+
 | 
			
		||||
+	LOG_DEBUG("Timed out waiting for the NVMC to be ready");
 | 
			
		||||
+	return ERROR_FLASH_BUSY;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_nvmc_erase_enable(struct nrf52_info *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_wait_for_nvmc(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = target_write_u32(chip->target,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_ADDR,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_EEN);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to configure the NVMC for erasing");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return res;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_nvmc_write_enable(struct nrf52_info *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_wait_for_nvmc(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = target_write_u32(chip->target,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_ADDR,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_WEN);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to configure the NVMC for writing");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return res;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_nvmc_read_only(struct nrf52_info *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_wait_for_nvmc(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = target_write_u32(chip->target,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_ADDR,
 | 
			
		||||
+						NRF52_NVMC_CONFIG_REN);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to configure the NVMC for read-only");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return res;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_nvmc_generic_erase(struct nrf52_info *chip,
 | 
			
		||||
+								uint32_t erase_register,
 | 
			
		||||
+								uint32_t erase_value)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_nvmc_erase_enable(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = target_write_u32(chip->target,
 | 
			
		||||
+						erase_register,
 | 
			
		||||
+						erase_value);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		LOG_ERROR("Failed to write NVMC erase register");
 | 
			
		||||
+
 | 
			
		||||
+	return nrf52_nvmc_read_only(chip);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_protect_check(struct flash_bank *bank)
 | 
			
		||||
+{
 | 
			
		||||
+	LOG_WARNING("nrf52_protect_check() is not implemented for nRF52 series devices yet");
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_protect(struct flash_bank *bank, int set, int first, int last)
 | 
			
		||||
+{
 | 
			
		||||
+	LOG_WARNING("nrf52_protect() is not implemented for nRF52 series devices yet");
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static struct flash_sector *nrf52_find_sector_by_address(struct flash_bank *bank, uint32_t address)
 | 
			
		||||
+{
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	for (int i = 0; i < bank->num_sectors; i++)
 | 
			
		||||
+		if (bank->sectors[i].offset <= address &&
 | 
			
		||||
+			address < (bank->sectors[i].offset + chip->code_page_size)) {
 | 
			
		||||
+			return &bank->sectors[i];
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	return NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_erase_all(struct nrf52_info *chip)
 | 
			
		||||
+{
 | 
			
		||||
+	LOG_DEBUG("Erasing all non-volatile memory");
 | 
			
		||||
+	return nrf52_nvmc_generic_erase(chip,
 | 
			
		||||
+								NRF52_NVMC_ERASEALL_ADDR,
 | 
			
		||||
+								0x01);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_erase_page(struct flash_bank *bank,
 | 
			
		||||
+							struct nrf52_info *chip,
 | 
			
		||||
+							struct flash_sector *sector)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+
 | 
			
		||||
+	LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
 | 
			
		||||
+	if (sector->is_protected == 1) {
 | 
			
		||||
+		LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
 | 
			
		||||
+		return ERROR_FAIL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (bank->base == NRF52_UICR_BASE_ADDR) {
 | 
			
		||||
+		res = nrf52_nvmc_generic_erase(chip,
 | 
			
		||||
+									NRF52_NVMC_ERASEUICR_ADDR,
 | 
			
		||||
+									0x00000001);
 | 
			
		||||
+	} else {
 | 
			
		||||
+		res = nrf52_nvmc_generic_erase(chip,
 | 
			
		||||
+									NRF52_NVMC_ERASEPAGE_ADDR,
 | 
			
		||||
+									sector->offset);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (res == ERROR_OK)
 | 
			
		||||
+		sector->is_erased = 1;
 | 
			
		||||
+	return res;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const uint8_t nrf52_flash_write_code[] = {
 | 
			
		||||
+	/* See contrib/loaders/flash/cortex-m0.S */
 | 
			
		||||
+	/* <wait_fifo>: */
 | 
			
		||||
+	0x0d, 0x68,		/* ldr	r5,	[r1,	#0] */
 | 
			
		||||
+	0x00, 0x2d,		/* cmp	r5,	#0 */
 | 
			
		||||
+	0x0b, 0xd0,		/* beq.n	1e <exit> */
 | 
			
		||||
+	0x4c, 0x68,		/* ldr	r4,	[r1,	#4] */
 | 
			
		||||
+	0xac, 0x42,		/* cmp	r4,	r5 */
 | 
			
		||||
+	0xf9, 0xd0,		/* beq.n	0 <wait_fifo> */
 | 
			
		||||
+	0x20, 0xcc,		/* ldmia	r4!,	{r5} */
 | 
			
		||||
+	0x20, 0xc3,		/* stmia	r3!,	{r5} */
 | 
			
		||||
+	0x94, 0x42,		/* cmp	r4,	r2 */
 | 
			
		||||
+	0x01, 0xd3,		/* bcc.n	18 <no_wrap> */
 | 
			
		||||
+	0x0c, 0x46,		/* mov	r4,	r1 */
 | 
			
		||||
+	0x08, 0x34,		/* adds	r4,	#8 */
 | 
			
		||||
+	/* <no_wrap>: */
 | 
			
		||||
+	0x4c, 0x60,		/* str	r4, [r1,	#4] */
 | 
			
		||||
+	0x04, 0x38,		/* subs	r0, #4 */
 | 
			
		||||
+	0xf0, 0xd1,		/* bne.n	0 <wait_fifo> */
 | 
			
		||||
+	/* <exit>: */
 | 
			
		||||
+	0x00, 0xbe		/* bkpt	0x0000 */
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+/* Start a low level flash write for the specified region */
 | 
			
		||||
+static int nrf52_ll_flash_write(struct nrf52_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
 | 
			
		||||
+{
 | 
			
		||||
+	struct target *target = chip->target;
 | 
			
		||||
+	uint32_t buffer_size = 8192;
 | 
			
		||||
+	struct working_area *write_algorithm;
 | 
			
		||||
+	struct working_area *source;
 | 
			
		||||
+	uint32_t address = NRF52_FLASH_BASE_ADDR + offset;
 | 
			
		||||
+	struct reg_param reg_params[4];
 | 
			
		||||
+	struct armv7m_algorithm armv7m_info;
 | 
			
		||||
+	int retval = ERROR_OK;
 | 
			
		||||
+
 | 
			
		||||
+	LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
 | 
			
		||||
+	assert(bytes % 4 == 0);
 | 
			
		||||
+
 | 
			
		||||
+	/* allocate working area with flash programming code */
 | 
			
		||||
+	if (target_alloc_working_area(target, sizeof(nrf52_flash_write_code),
 | 
			
		||||
+			&write_algorithm) != ERROR_OK) {
 | 
			
		||||
+		LOG_WARNING("no working area available, falling back to slow memory writes");
 | 
			
		||||
+
 | 
			
		||||
+		for (; bytes > 0; bytes -= 4) {
 | 
			
		||||
+			retval = target_write_memory(chip->target,
 | 
			
		||||
+										offset, 4, 1, buffer);
 | 
			
		||||
+			if (retval != ERROR_OK)
 | 
			
		||||
+				return retval;
 | 
			
		||||
+
 | 
			
		||||
+			retval = nrf52_wait_for_nvmc(chip);
 | 
			
		||||
+			if (retval != ERROR_OK)
 | 
			
		||||
+				return retval;
 | 
			
		||||
+
 | 
			
		||||
+			offset += 4;
 | 
			
		||||
+			buffer += 4;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		return ERROR_OK;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	LOG_WARNING("using fast async flash loader. This is currently supported");
 | 
			
		||||
+	LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
 | 
			
		||||
+	LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf52.cfg to disable it");
 | 
			
		||||
+
 | 
			
		||||
+	retval = target_write_buffer(target, write_algorithm->address,
 | 
			
		||||
+				sizeof(nrf52_flash_write_code),
 | 
			
		||||
+				nrf52_flash_write_code);
 | 
			
		||||
+	if (retval != ERROR_OK)
 | 
			
		||||
+		return retval;
 | 
			
		||||
+
 | 
			
		||||
+	/* memory buffer */
 | 
			
		||||
+	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
 | 
			
		||||
+		buffer_size /= 2;
 | 
			
		||||
+		buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
 | 
			
		||||
+		if (buffer_size <= 256) {
 | 
			
		||||
+			/* free working area, write algorithm already allocated */
 | 
			
		||||
+			target_free_working_area(target, write_algorithm);
 | 
			
		||||
+
 | 
			
		||||
+			LOG_WARNING("No large enough working area available, can't do block memory writes");
 | 
			
		||||
+			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
 | 
			
		||||
+	armv7m_info.core_mode = ARM_MODE_THREAD;
 | 
			
		||||
+
 | 
			
		||||
+	init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);	/* byte count */
 | 
			
		||||
+	init_reg_param(®_params[1], "r1", 32, PARAM_OUT);	/* buffer start */
 | 
			
		||||
+	init_reg_param(®_params[2], "r2", 32, PARAM_OUT);	/* buffer end */
 | 
			
		||||
+	init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT);	/* target address */
 | 
			
		||||
+
 | 
			
		||||
+	buf_set_u32(reg_params[0].value, 0, 32, bytes);
 | 
			
		||||
+	buf_set_u32(reg_params[1].value, 0, 32, source->address);
 | 
			
		||||
+	buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
 | 
			
		||||
+	buf_set_u32(reg_params[3].value, 0, 32, address);
 | 
			
		||||
+
 | 
			
		||||
+	retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
 | 
			
		||||
+			0, NULL,
 | 
			
		||||
+			4, reg_params,
 | 
			
		||||
+			source->address, source->size,
 | 
			
		||||
+			write_algorithm->address, 0,
 | 
			
		||||
+			&armv7m_info);
 | 
			
		||||
+
 | 
			
		||||
+	target_free_working_area(target, source);
 | 
			
		||||
+	target_free_working_area(target, write_algorithm);
 | 
			
		||||
+
 | 
			
		||||
+	destroy_reg_param(®_params[0]);
 | 
			
		||||
+	destroy_reg_param(®_params[1]);
 | 
			
		||||
+	destroy_reg_param(®_params[2]);
 | 
			
		||||
+	destroy_reg_param(®_params[3]);
 | 
			
		||||
+
 | 
			
		||||
+	return retval;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+/* Check and erase flash sectors in specified range, then start a low level page write.
 | 
			
		||||
+   start/end must be sector aligned.
 | 
			
		||||
+*/
 | 
			
		||||
+static int nrf52_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	uint32_t offset;
 | 
			
		||||
+	struct flash_sector *sector;
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	assert(start % chip->code_page_size == 0);
 | 
			
		||||
+	assert(end % chip->code_page_size == 0);
 | 
			
		||||
+
 | 
			
		||||
+	/* Erase all sectors */
 | 
			
		||||
+	for (offset = start; offset < end; offset += chip->code_page_size) {
 | 
			
		||||
+		sector = nrf52_find_sector_by_address(bank, offset);
 | 
			
		||||
+
 | 
			
		||||
+		if (sector == NULL) {
 | 
			
		||||
+			LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
 | 
			
		||||
+			return ERROR_FLASH_SECTOR_INVALID;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (sector->is_protected == 1) {
 | 
			
		||||
+			LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
 | 
			
		||||
+			return ERROR_FAIL;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (sector->is_erased != 1) {	/* 1 = erased, 0= not erased, -1 = unknown */
 | 
			
		||||
+			res = nrf52_erase_page(bank, chip, sector);
 | 
			
		||||
+			if (res != ERROR_OK) {
 | 
			
		||||
+				LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
 | 
			
		||||
+				return res;
 | 
			
		||||
+			}
 | 
			
		||||
+		}
 | 
			
		||||
+		sector->is_erased = 1;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_nvmc_write_enable(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_ll_flash_write(chip, start, buffer, (end - start));
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to write FLASH");
 | 
			
		||||
+		nrf52_nvmc_read_only(chip);
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return nrf52_nvmc_read_only(chip);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_erase(struct flash_bank *bank, int first, int last)
 | 
			
		||||
+{
 | 
			
		||||
+	int res = ERROR_OK;
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	/* For each sector to be erased */
 | 
			
		||||
+	for (int s = first; s <= last && res == ERROR_OK; s++)
 | 
			
		||||
+		res = nrf52_erase_page(bank, chip, &bank->sectors[s]);
 | 
			
		||||
+
 | 
			
		||||
+	return res;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_code_flash_write(struct flash_bank *bank,
 | 
			
		||||
+								struct nrf52_info *chip,
 | 
			
		||||
+								const uint8_t *buffer, uint32_t offset, uint32_t count)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	/* Need to perform reads to fill any gaps we need to preserve in the first page,
 | 
			
		||||
+	   before the start of buffer, or in the last page, after the end of buffer */
 | 
			
		||||
+	uint32_t first_page = offset / chip->code_page_size;
 | 
			
		||||
+	uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
 | 
			
		||||
+
 | 
			
		||||
+	uint32_t first_page_offset = first_page * chip->code_page_size;
 | 
			
		||||
+	uint32_t last_page_offset = last_page * chip->code_page_size;
 | 
			
		||||
+
 | 
			
		||||
+	LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
 | 
			
		||||
+			offset, offset+count, first_page_offset, last_page_offset);
 | 
			
		||||
+
 | 
			
		||||
+	uint32_t page_cnt = last_page - first_page;
 | 
			
		||||
+	uint8_t buffer_to_flash[page_cnt * chip->code_page_size];
 | 
			
		||||
+
 | 
			
		||||
+	/* Fill in any space between start of first page and start of buffer */
 | 
			
		||||
+	uint32_t pre = offset - first_page_offset;
 | 
			
		||||
+	if (pre > 0) {
 | 
			
		||||
+		res = target_read_memory(bank->target, first_page_offset, 1, pre, buffer_to_flash);
 | 
			
		||||
+		if (res != ERROR_OK)
 | 
			
		||||
+			return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	/* Fill in main contents of buffer */
 | 
			
		||||
+	memcpy(buffer_to_flash + pre, buffer, count);
 | 
			
		||||
+
 | 
			
		||||
+	/* Fill in any space between end of buffer and end of last page */
 | 
			
		||||
+	uint32_t post = last_page_offset - (offset + count);
 | 
			
		||||
+	if (post > 0) {
 | 
			
		||||
+		/* Retrieve the full row contents from Flash */
 | 
			
		||||
+		res = target_read_memory(bank->target, offset + count, 1, post, buffer_to_flash + pre + count);
 | 
			
		||||
+		if (res != ERROR_OK)
 | 
			
		||||
+			return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return nrf52_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_uicr_flash_write(struct flash_bank *bank,
 | 
			
		||||
+								struct nrf52_info *chip,
 | 
			
		||||
+								const uint8_t *buffer, uint32_t offset, uint32_t count)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	uint32_t nrf52_uicr_size = chip->code_page_size;
 | 
			
		||||
+	uint8_t uicr[nrf52_uicr_size];
 | 
			
		||||
+	struct flash_sector *sector = &bank->sectors[0];
 | 
			
		||||
+
 | 
			
		||||
+	if ((offset + count) > nrf52_uicr_size)
 | 
			
		||||
+		return ERROR_FAIL;
 | 
			
		||||
+
 | 
			
		||||
+	res = target_read_memory(bank->target, NRF52_UICR_BASE_ADDR, 1, nrf52_uicr_size, uicr);
 | 
			
		||||
+
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	if (sector->is_erased != 1) {
 | 
			
		||||
+		res = nrf52_erase_page(bank, chip, sector);
 | 
			
		||||
+		if (res != ERROR_OK)
 | 
			
		||||
+			return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	memcpy(&uicr[offset], buffer, count);
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_nvmc_write_enable(chip);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_ll_flash_write(chip, NRF52_UICR_BASE_ADDR, uicr, nrf52_uicr_size);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		nrf52_nvmc_read_only(chip);
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return nrf52_nvmc_read_only(chip);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_write(struct flash_bank *bank, const uint8_t *buffer,
 | 
			
		||||
+					uint32_t offset, uint32_t count)
 | 
			
		||||
+{
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+FLASH_BANK_COMMAND_HANDLER(nrf52_flash_bank_command)
 | 
			
		||||
+{
 | 
			
		||||
+	static struct nrf52_info *chip;
 | 
			
		||||
+
 | 
			
		||||
+	assert(bank != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	switch (bank->base) {
 | 
			
		||||
+	case NRF52_FLASH_BASE_ADDR:
 | 
			
		||||
+		bank->bank_number = 0;
 | 
			
		||||
+		break;
 | 
			
		||||
+	case NRF52_UICR_BASE_ADDR:
 | 
			
		||||
+		bank->bank_number = 1;
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		LOG_ERROR("Invalid bank address 0x%08" PRIx32, bank->base);
 | 
			
		||||
+		return ERROR_FAIL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (!chip) {
 | 
			
		||||
+		/* Create a new chip */
 | 
			
		||||
+		chip = calloc(1, sizeof(*chip));
 | 
			
		||||
+		assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+		chip->target = bank->target;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	switch (bank->base) {
 | 
			
		||||
+	case NRF52_FLASH_BASE_ADDR:
 | 
			
		||||
+		chip->bank[bank->bank_number].write = nrf52_code_flash_write;
 | 
			
		||||
+		break;
 | 
			
		||||
+	case NRF52_UICR_BASE_ADDR:
 | 
			
		||||
+		chip->bank[bank->bank_number].write = nrf52_uicr_flash_write;
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	chip->bank[bank->bank_number].probed = false;
 | 
			
		||||
+	bank->driver_priv = chip;
 | 
			
		||||
+
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+COMMAND_HANDLER(nrf52_handle_mass_erase_command)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	struct flash_bank *bank = NULL;
 | 
			
		||||
+	struct target *target = get_current_target(CMD_CTX);
 | 
			
		||||
+
 | 
			
		||||
+	res = get_flash_bank_by_addr(target, NRF52_FLASH_BASE_ADDR, true, &bank);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	assert(bank != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_erase_all(chip);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to erase the chip");
 | 
			
		||||
+		nrf52_protect_check(bank);
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	for (int i = 0; i < bank->num_sectors; i++)
 | 
			
		||||
+		bank->sectors[i].is_erased = 1;
 | 
			
		||||
+
 | 
			
		||||
+	res = nrf52_protect_check(bank);
 | 
			
		||||
+	if (res != ERROR_OK) {
 | 
			
		||||
+		LOG_ERROR("Failed to check chip's write protection");
 | 
			
		||||
+		return res;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	res = get_flash_bank_by_addr(target, NRF52_UICR_BASE_ADDR, true, &bank);
 | 
			
		||||
+	if (res != ERROR_OK)
 | 
			
		||||
+		return res;
 | 
			
		||||
+
 | 
			
		||||
+	bank->sectors[0].is_erased = 1;
 | 
			
		||||
+
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int nrf52_info(struct flash_bank *bank, char *buf, int buf_size)
 | 
			
		||||
+{
 | 
			
		||||
+	int res;
 | 
			
		||||
+	uint32_t ficr[2];
 | 
			
		||||
+	struct nrf52_info *chip = bank->driver_priv;
 | 
			
		||||
+	assert(chip != NULL);
 | 
			
		||||
+
 | 
			
		||||
+	res = target_read_u32(chip->target, NRF52_FICR_CODEPAGESIZE_ADDR, &ficr[0]);
 | 
			
		||||
+		if (res != ERROR_OK) {
 | 
			
		||||
+			LOG_ERROR("Couldn't read NVMC_READY register");
 | 
			
		||||
+			return res;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	res = target_read_u32(chip->target, NRF52_FICR_CODESIZE_ADDR, &ficr[1]);
 | 
			
		||||
+		if (res != ERROR_OK) {
 | 
			
		||||
+			LOG_ERROR("Couldn't read NVMC_READY register");
 | 
			
		||||
+			return res;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	snprintf(buf, buf_size,
 | 
			
		||||
+			"\n--------nRF52 Series Device--------\n\n"
 | 
			
		||||
+			"\n[factory information control block]\n"
 | 
			
		||||
+			"code page size: %"PRIu32"B\n"
 | 
			
		||||
+			"code memory size: %"PRIu32"kB\n",
 | 
			
		||||
+			ficr[0],
 | 
			
		||||
+			(ficr[1] * ficr[0]) / 1024);
 | 
			
		||||
+
 | 
			
		||||
+	return ERROR_OK;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const struct command_registration nrf52_exec_command_handlers[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.name		= "mass_erase",
 | 
			
		||||
+		.handler	= nrf52_handle_mass_erase_command,
 | 
			
		||||
+		.mode		= COMMAND_EXEC,
 | 
			
		||||
+		.help		= "Erase all flash contents of the chip.",
 | 
			
		||||
+	},
 | 
			
		||||
+	COMMAND_REGISTRATION_DONE
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct command_registration nrf52_command_handlers[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.name	= "nrf52",
 | 
			
		||||
+		.mode	= COMMAND_ANY,
 | 
			
		||||
+		.help	= "nrf52 flash command group",
 | 
			
		||||
+		.usage	= "",
 | 
			
		||||
+		.chain	= nrf52_exec_command_handlers,
 | 
			
		||||
+	},
 | 
			
		||||
+	COMMAND_REGISTRATION_DONE
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+struct flash_driver nrf52_flash = {
 | 
			
		||||
+	.name			= "nrf52",
 | 
			
		||||
+	.commands		= nrf52_command_handlers,
 | 
			
		||||
+	.flash_bank_command	= nrf52_flash_bank_command,
 | 
			
		||||
+	.info			= nrf52_info,
 | 
			
		||||
+	.erase			= nrf52_erase,
 | 
			
		||||
+	.protect		= nrf52_protect,
 | 
			
		||||
+	.write			= nrf52_write,
 | 
			
		||||
+	.read			= default_flash_read,
 | 
			
		||||
+	.probe			= nrf52_probe,
 | 
			
		||||
+	.auto_probe		= nrf52_auto_probe,
 | 
			
		||||
+	.erase_check	= default_flash_blank_check,
 | 
			
		||||
+	.protect_check	= nrf52_protect_check,
 | 
			
		||||
+};
 | 
			
		||||
diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg
 | 
			
		||||
index c1cbf1a..a2567ff 100644
 | 
			
		||||
--- a/tcl/target/nrf52.cfg
 | 
			
		||||
+++ b/tcl/target/nrf52.cfg
 | 
			
		||||
@@ -5,15 +5,22 @@
 | 
			
		||||
 source [find target/swj-dp.tcl]
 | 
			
		||||
 
 | 
			
		||||
 if { [info exists CHIPNAME] } {
 | 
			
		||||
-	set _CHIPNAME $CHIPNAME
 | 
			
		||||
+   set _CHIPNAME $CHIPNAME
 | 
			
		||||
 } else {
 | 
			
		||||
-	set _CHIPNAME nrf52
 | 
			
		||||
+   set _CHIPNAME nrf52
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+# Work-area is a space in RAM used for flash programming, by default use 16kB.
 | 
			
		||||
+if { [info exists WORKAREASIZE] } {
 | 
			
		||||
+   set _WORKAREASIZE $WORKAREASIZE
 | 
			
		||||
+} else {
 | 
			
		||||
+   set _WORKAREASIZE 0x4000
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 if { [info exists CPUTAPID] } {
 | 
			
		||||
-	set _CPUTAPID $CPUTAPID
 | 
			
		||||
+   set _CPUTAPID $CPUTAPID
 | 
			
		||||
 } else {
 | 
			
		||||
-	set _CPUTAPID 0x2ba01477
 | 
			
		||||
+   set _CPUTAPID 0x2ba01477
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
 | 
			
		||||
@@ -21,8 +28,15 @@ swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
 | 
			
		||||
 set _TARGETNAME $_CHIPNAME.cpu
 | 
			
		||||
 target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME
 | 
			
		||||
 
 | 
			
		||||
-adapter_khz 10000
 | 
			
		||||
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
 | 
			
		||||
 
 | 
			
		||||
-if { ![using_hla] } {
 | 
			
		||||
-	cortex_m reset_config sysresetreq
 | 
			
		||||
+if {![using_hla]} {
 | 
			
		||||
+   cortex_m reset_config sysresetreq
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
+flash bank $_CHIPNAME.flash nrf52 0x00000000 0 1 1 $_TARGETNAME
 | 
			
		||||
+flash bank $_CHIPNAME.uicr nrf52 0x10001000 0 1 1 $_TARGETNAME
 | 
			
		||||
+
 | 
			
		||||
+adapter_khz 1000
 | 
			
		||||
+
 | 
			
		||||
+$_TARGETNAME configure -event reset-end {}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +29,7 @@
 | 
			
		|||
;;; Copyright © 2016 Marius Bakke <mbakke@fastmail.com>
 | 
			
		||||
;;; Copyright © 2016 Stefan Reichoer <stefan@xsteve.at>
 | 
			
		||||
;;; Copyright © 2016 Dylan Jeffers <sapientech@sapientech@openmailbox.org>
 | 
			
		||||
;;; Copyright © 2016 Alex Vong <alexvong1995@gmail.com>
 | 
			
		||||
;;;
 | 
			
		||||
;;; This file is part of GNU Guix.
 | 
			
		||||
;;;
 | 
			
		||||
| 
						 | 
				
			
			@ -3172,6 +3173,30 @@ writing C extensions for Python as easy as Python itself.")
 | 
			
		|||
    (inputs
 | 
			
		||||
     `(("python-2" ,python-2))))) ; this is not automatically changed
 | 
			
		||||
 | 
			
		||||
;; The RPython toolchain currently does not support Python 3.
 | 
			
		||||
(define-public python2-rpython
 | 
			
		||||
  (package
 | 
			
		||||
    (name "python2-rpython")
 | 
			
		||||
    (version "0.1.4")
 | 
			
		||||
    (source
 | 
			
		||||
     (origin
 | 
			
		||||
       (method url-fetch)
 | 
			
		||||
       (uri (pypi-uri "rpython" version))
 | 
			
		||||
       (sha256
 | 
			
		||||
        (base32
 | 
			
		||||
         "07pps06fq4c4wmi5ii0sgh9zgwniz5y7frqhm28g3a154l163fxc"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (arguments `(#:python ,python-2))
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("python2-pytest" ,python2-pytest) ; needed for running tests
 | 
			
		||||
       ("python2-setuptools" ,python2-setuptools)))
 | 
			
		||||
    (home-page "https://rpython.readthedocs.org")
 | 
			
		||||
    (synopsis "Framework for implementing interpreters and virtual machines")
 | 
			
		||||
    (description "RPython is a translation and support framework for
 | 
			
		||||
producing implementations of dynamic languages, emphasizing a clean separation
 | 
			
		||||
between language specification and implementation aspects.")
 | 
			
		||||
    (license license:expat)))
 | 
			
		||||
 | 
			
		||||
;; This version of numpy is missing the documentation and is only used to
 | 
			
		||||
;; build matplotlib which is required to build numpy's documentation.
 | 
			
		||||
(define python-numpy-bootstrap
 | 
			
		||||
| 
						 | 
				
			
			@ -5258,30 +5283,28 @@ connection to each user.")
 | 
			
		|||
(define-public python-waf
 | 
			
		||||
  (package
 | 
			
		||||
    (name "python-waf")
 | 
			
		||||
    (version "1.9.1")
 | 
			
		||||
    (version "1.9.5")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append "https://waf.io/"
 | 
			
		||||
              (uri (string-append "http://waf.io/"
 | 
			
		||||
                                  "waf-" version ".tar.bz2"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "1nc4qaqx2vsanlpp9mcwvf91xjqpkvcc6fcxd5sb4fwvaxamw5v6"))))
 | 
			
		||||
                "1sl3ipi2czds57rlzjnpdzqa0skx8asfvmh3qmibpvdwf15rpppg"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     '(#:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         (replace 'build
 | 
			
		||||
                  (lambda _
 | 
			
		||||
                    (zero? (begin
 | 
			
		||||
                             (system* "python" "waf-light" "configure")
 | 
			
		||||
                             (system* "python" "waf-light" "build")))))
 | 
			
		||||
           (lambda _
 | 
			
		||||
             (zero? (system* "python" "waf-light" "configure" "build"))))
 | 
			
		||||
         (replace 'check
 | 
			
		||||
                  (lambda _
 | 
			
		||||
                    (zero? (system* "python" "waf" "--version"))))
 | 
			
		||||
           (lambda _
 | 
			
		||||
             (zero? (system* "python" "waf" "--version"))))
 | 
			
		||||
         (replace 'install
 | 
			
		||||
                  (lambda _
 | 
			
		||||
                    (copy-file "waf" %output))))))
 | 
			
		||||
    (home-page "https://waf.io/")
 | 
			
		||||
           (lambda _
 | 
			
		||||
             (copy-file "waf" %output))))))
 | 
			
		||||
    (home-page "http://waf.io/")
 | 
			
		||||
    (synopsis "Python-based build system")
 | 
			
		||||
    (description
 | 
			
		||||
     "Waf is a Python-based framework for configuring, compiling and installing
 | 
			
		||||
| 
						 | 
				
			
			@ -9652,7 +9675,9 @@ focus on event-based network programming and multiprotocol integration.")
 | 
			
		|||
          "0nb4h08di432lv7dy2v9kpwgk0w92f24sqc2hw2s9vwr5b8v8xvj"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("python-twisted" ,python-twisted)))
 | 
			
		||||
     `(("python-pyev" ,python-pyev)
 | 
			
		||||
       ("python-tornado" ,python-tornado)
 | 
			
		||||
       ("python-twisted" ,python-twisted)))
 | 
			
		||||
    (home-page "https://pika.readthedocs.org")
 | 
			
		||||
    (synopsis "Pure Python AMQP Client Library")
 | 
			
		||||
    (description
 | 
			
		||||
| 
						 | 
				
			
			@ -10214,6 +10239,8 @@ implementation for Python.")
 | 
			
		|||
        (base32
 | 
			
		||||
          "1vyjd0b7wciv55i19l44zy0adx8q7ss79lhy2r9d1rwz2y4822zg"))))
 | 
			
		||||
  (build-system python-build-system)
 | 
			
		||||
  (arguments
 | 
			
		||||
   '(#:tests? #f)) ; The test suite uses some Windows-specific data types.
 | 
			
		||||
  (inputs `(("python-wcwidth" ,python-wcwidth)
 | 
			
		||||
            ("python-pygments" ,python-pygments)))
 | 
			
		||||
  (native-inputs `(("python-six" ,python-six)))
 | 
			
		||||
| 
						 | 
				
			
			@ -10681,6 +10708,8 @@ List.")
 | 
			
		|||
        (base32
 | 
			
		||||
         "06lx603gdwad5hc3hmn763ngq0rq9bzz1ni3ga72nzk5n872arkd"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     '(#:tests? #f)) ; The test suite requires network access.
 | 
			
		||||
    (home-page "https://github.com/pombredanne/python-publicsuffix2")
 | 
			
		||||
    (synopsis "Get a public suffix for a domain name using the Public Suffix List")
 | 
			
		||||
    (description "Get a public suffix for a domain name using the Public Suffix
 | 
			
		||||
| 
						 | 
				
			
			@ -11477,3 +11506,36 @@ useful as a validator for JSON data.")
 | 
			
		|||
    (description
 | 
			
		||||
      "This package adds SQLAlchemy support to your Flask application.")
 | 
			
		||||
    (license license:bsd-3)))
 | 
			
		||||
 | 
			
		||||
(define-public python-pyev
 | 
			
		||||
  (package
 | 
			
		||||
    (name "python-pyev")
 | 
			
		||||
    (version "0.9.0")
 | 
			
		||||
    (source
 | 
			
		||||
      (origin
 | 
			
		||||
        (method url-fetch)
 | 
			
		||||
        (uri (pypi-uri "pyev" version))
 | 
			
		||||
        (sha256
 | 
			
		||||
         (base32
 | 
			
		||||
          "0rf603lc0s6zpa1nb25vhd8g4y337wg2wyz56i0agsdh7jchl0sx"))))
 | 
			
		||||
    (build-system python-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:tests? #f ; no test suite
 | 
			
		||||
       #:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         (add-after 'unpack 'patch
 | 
			
		||||
           (lambda* (#:key inputs #:allow-other-keys)
 | 
			
		||||
             (let ((libev (string-append (assoc-ref inputs "libev")
 | 
			
		||||
                                         "/lib/libev.so.4")))
 | 
			
		||||
               (substitute* "setup.py"
 | 
			
		||||
                 (("libev_dll_name = find_library\\(\\\"ev\\\"\\)")
 | 
			
		||||
                  (string-append "libev_dll_name = \"" libev "\"")))))))))
 | 
			
		||||
    (inputs
 | 
			
		||||
     `(("libev" ,libev)))
 | 
			
		||||
    (home-page "http://pythonhosted.org/pyev/")
 | 
			
		||||
    (synopsis "Python libev interface")
 | 
			
		||||
    (description "Pyev provides a Python interface to libev.")
 | 
			
		||||
    (license license:gpl3)))
 | 
			
		||||
 | 
			
		||||
(define-public python2-pyev
 | 
			
		||||
  (package-with-python2 python-pyev))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@
 | 
			
		|||
    (arguments
 | 
			
		||||
     `(;; gputils is required for PIC ports
 | 
			
		||||
       #:configure-flags
 | 
			
		||||
       '("--disable-pic14-port" "--disable-pic16-port")
 | 
			
		||||
       '("--disable-pic14-port" "--disable-pic16-port" "--enable-ucsim")
 | 
			
		||||
       #:phases
 | 
			
		||||
       (modify-phases %standard-phases
 | 
			
		||||
         (add-after 'unpack 'patch-makefile
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -434,14 +434,14 @@ standards (MPEG-2, MPEG-4 ASP/H.263, MPEG-4 AVC/H.264, and VC-1/VMW3).")
 | 
			
		|||
(define-public ffmpeg
 | 
			
		||||
  (package
 | 
			
		||||
    (name "ffmpeg")
 | 
			
		||||
    (version "3.1.5")
 | 
			
		||||
    (version "3.2")
 | 
			
		||||
    (source (origin
 | 
			
		||||
             (method url-fetch)
 | 
			
		||||
             (uri (string-append "https://ffmpeg.org/releases/ffmpeg-"
 | 
			
		||||
                                 version ".tar.xz"))
 | 
			
		||||
             (sha256
 | 
			
		||||
              (base32
 | 
			
		||||
               "16mqb1fs6ahqqv6a64dk4d8rp75ixdsipfzsz0vmc749yw2k3k29"))))
 | 
			
		||||
               "1nnmd3h9pr2zic08isjcm1cmvcyd0aimpayb9r4qy45bihdhrxw8"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (inputs
 | 
			
		||||
     `(("fontconfig" ,fontconfig)
 | 
			
		||||
| 
						 | 
				
			
			@ -1287,16 +1287,16 @@ capabilities.")
 | 
			
		|||
(define-public vapoursynth
 | 
			
		||||
  (package
 | 
			
		||||
    (name "vapoursynth")
 | 
			
		||||
    (version "34")
 | 
			
		||||
    (version "35")
 | 
			
		||||
    (source (origin
 | 
			
		||||
              (method url-fetch)
 | 
			
		||||
              (uri (string-append
 | 
			
		||||
                    "https://github.com/vapoursynth/vapoursynth/archive/R"
 | 
			
		||||
                    version ".tar.gz"))
 | 
			
		||||
              (file-name (string-append name "-" version))
 | 
			
		||||
              (file-name (string-append name "-" version ".tar.gz"))
 | 
			
		||||
              (sha256
 | 
			
		||||
               (base32
 | 
			
		||||
                "0rfldphg4gy3sdfffi5yzklqz93vsj2j6nny8snjbavnf161blyi"))))
 | 
			
		||||
                "0629ys2lf618n9cc644xlvx0vx52v2fp3sx14p4mx5rg9nlasb3n"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (native-inputs
 | 
			
		||||
     `(("autoconf" ,autoconf)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,14 +48,15 @@
 | 
			
		|||
(define-public vim
 | 
			
		||||
  (package
 | 
			
		||||
    (name "vim")
 | 
			
		||||
    (version "8.0")
 | 
			
		||||
    (version "8.0.0054")
 | 
			
		||||
    (source (origin
 | 
			
		||||
             (method url-fetch)
 | 
			
		||||
             (uri (string-append "ftp://ftp.vim.org/pub/vim/unix/vim-"
 | 
			
		||||
                                 version ".tar.bz2"))
 | 
			
		||||
             (uri (string-append "https://github.com/vim/vim/archive/v"
 | 
			
		||||
                                 version ".tar.gz"))
 | 
			
		||||
             (file-name (string-append name "-" version ".tar.gz"))
 | 
			
		||||
             (sha256
 | 
			
		||||
              (base32
 | 
			
		||||
               "1s34rf8089klsbdx5l0iw7vjymir0kzfrx8wb30s31wygnq29axc"))))
 | 
			
		||||
               "018my9vmvflww9yzrrzgdbja8j075yxqj0czg351r6wrndqiv9vq"))))
 | 
			
		||||
    (build-system gnu-build-system)
 | 
			
		||||
    (arguments
 | 
			
		||||
     `(#:test-target "test"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,7 +139,9 @@ and 'hexadecimal' can be used as well).\n"))
 | 
			
		|||
              (write-file file port #:select? select?)
 | 
			
		||||
              (force-output port)
 | 
			
		||||
              (get-hash))
 | 
			
		||||
            (call-with-input-file file port-sha256))))
 | 
			
		||||
            (match file
 | 
			
		||||
              ("-" (port-sha256 (current-input-port)))
 | 
			
		||||
              (_   (call-with-input-file file port-sha256))))))
 | 
			
		||||
 | 
			
		||||
    (match args
 | 
			
		||||
      ((file)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,171 +40,6 @@
 | 
			
		|||
namespace nix {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MakeError(SQLiteError, Error);
 | 
			
		||||
MakeError(SQLiteBusy, SQLiteError);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void throwSQLiteError(sqlite3 * db, const format & f)
 | 
			
		||||
    __attribute__ ((noreturn));
 | 
			
		||||
 | 
			
		||||
static void throwSQLiteError(sqlite3 * db, const format & f)
 | 
			
		||||
{
 | 
			
		||||
    int err = sqlite3_errcode(db);
 | 
			
		||||
    if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) {
 | 
			
		||||
        if (err == SQLITE_PROTOCOL)
 | 
			
		||||
            printMsg(lvlError, "warning: SQLite database is busy (SQLITE_PROTOCOL)");
 | 
			
		||||
        else {
 | 
			
		||||
            static bool warned = false;
 | 
			
		||||
            if (!warned) {
 | 
			
		||||
                printMsg(lvlError, "warning: SQLite database is busy");
 | 
			
		||||
                warned = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        /* Sleep for a while since retrying the transaction right away
 | 
			
		||||
           is likely to fail again. */
 | 
			
		||||
#if HAVE_NANOSLEEP
 | 
			
		||||
        struct timespec t;
 | 
			
		||||
        t.tv_sec = 0;
 | 
			
		||||
        t.tv_nsec = (random() % 100) * 1000 * 1000; /* <= 0.1s */
 | 
			
		||||
        nanosleep(&t, 0);
 | 
			
		||||
#else
 | 
			
		||||
        sleep(1);
 | 
			
		||||
#endif
 | 
			
		||||
        throw SQLiteBusy(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Convenience macros for retrying a SQLite transaction. */
 | 
			
		||||
#define retry_sqlite while (1) { try {
 | 
			
		||||
#define end_retry_sqlite break; } catch (SQLiteBusy & e) { } }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SQLite::~SQLite()
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        if (db && sqlite3_close(db) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "closing database");
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        ignoreException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::create(sqlite3 * db, const string & s)
 | 
			
		||||
{
 | 
			
		||||
    checkInterrupt();
 | 
			
		||||
    assert(!stmt);
 | 
			
		||||
    if (sqlite3_prepare_v2(db, s.c_str(), -1, &stmt, 0) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "creating statement");
 | 
			
		||||
    this->db = db;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::reset()
 | 
			
		||||
{
 | 
			
		||||
    assert(stmt);
 | 
			
		||||
    /* Note: sqlite3_reset() returns the error code for the most
 | 
			
		||||
       recent call to sqlite3_step().  So ignore it. */
 | 
			
		||||
    sqlite3_reset(stmt);
 | 
			
		||||
    curArg = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::~SQLiteStmt()
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        if (stmt && sqlite3_finalize(stmt) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "finalizing statement");
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        ignoreException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::bind(const string & value)
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_bind_text(stmt, curArg++, value.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "binding argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::bind(int value)
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_bind_int(stmt, curArg++, value) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "binding argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::bind64(long long value)
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_bind_int64(stmt, curArg++, value) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "binding argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::bind()
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_bind_null(stmt, curArg++) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "binding argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Helper class to ensure that prepared statements are reset when
 | 
			
		||||
   leaving the scope that uses them.  Unfinished prepared statements
 | 
			
		||||
   prevent transactions from being aborted, and can cause locks to be
 | 
			
		||||
   kept when they should be released. */
 | 
			
		||||
struct SQLiteStmtUse
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmt & stmt;
 | 
			
		||||
    SQLiteStmtUse(SQLiteStmt & stmt) : stmt(stmt)
 | 
			
		||||
    {
 | 
			
		||||
        stmt.reset();
 | 
			
		||||
    }
 | 
			
		||||
    ~SQLiteStmtUse()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            stmt.reset();
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
            ignoreException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SQLiteTxn
 | 
			
		||||
{
 | 
			
		||||
    bool active;
 | 
			
		||||
    sqlite3 * db;
 | 
			
		||||
 | 
			
		||||
    SQLiteTxn(sqlite3 * db) : active(false) {
 | 
			
		||||
        this->db = db;
 | 
			
		||||
        if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "starting transaction");
 | 
			
		||||
        active = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void commit()
 | 
			
		||||
    {
 | 
			
		||||
        if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "committing transaction");
 | 
			
		||||
        active = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~SQLiteTxn()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            if (active && sqlite3_exec(db, "rollback;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
                throwSQLiteError(db, "aborting transaction");
 | 
			
		||||
        } catch (...) {
 | 
			
		||||
            ignoreException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void checkStoreNotSymlink()
 | 
			
		||||
{
 | 
			
		||||
    if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
 | 
			
		||||
| 
						 | 
				
			
			@ -494,6 +329,7 @@ void LocalStore::openDB(bool create)
 | 
			
		|||
    // ensure efficient lookup.
 | 
			
		||||
    stmtQueryPathFromHashPart.create(db,
 | 
			
		||||
        "select path from ValidPaths where path >= ? limit 1;");
 | 
			
		||||
    stmtQueryValidPaths.create(db, "select path from ValidPaths");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -688,23 +524,16 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool checkOutputs)
 | 
			
		||||
uint64_t LocalStore::addValidPath(const ValidPathInfo & info, bool checkOutputs)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtRegisterValidPath);
 | 
			
		||||
    stmtRegisterValidPath.bind(info.path);
 | 
			
		||||
    stmtRegisterValidPath.bind("sha256:" + printHash(info.hash));
 | 
			
		||||
    stmtRegisterValidPath.bind(info.registrationTime == 0 ? time(0) : info.registrationTime);
 | 
			
		||||
    if (info.deriver != "")
 | 
			
		||||
        stmtRegisterValidPath.bind(info.deriver);
 | 
			
		||||
    else
 | 
			
		||||
        stmtRegisterValidPath.bind(); // null
 | 
			
		||||
    if (info.narSize != 0)
 | 
			
		||||
        stmtRegisterValidPath.bind64(info.narSize);
 | 
			
		||||
    else
 | 
			
		||||
        stmtRegisterValidPath.bind(); // null
 | 
			
		||||
    if (sqlite3_step(stmtRegisterValidPath) != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(db, format("registering valid path `%1%' in database") % info.path);
 | 
			
		||||
    unsigned long long id = sqlite3_last_insert_rowid(db);
 | 
			
		||||
    stmtRegisterValidPath.use()
 | 
			
		||||
        (info.path)
 | 
			
		||||
        ("sha256:" + printHash(info.hash))
 | 
			
		||||
        (info.registrationTime == 0 ? time(0) : info.registrationTime)
 | 
			
		||||
        (info.deriver, info.deriver != "")
 | 
			
		||||
        (info.narSize, info.narSize != 0)
 | 
			
		||||
        .exec();
 | 
			
		||||
    uint64_t id = sqlite3_last_insert_rowid(db);
 | 
			
		||||
 | 
			
		||||
    /* If this is a derivation, then store the derivation outputs in
 | 
			
		||||
       the database.  This is useful for the garbage collector: it can
 | 
			
		||||
| 
						 | 
				
			
			@ -720,13 +549,12 @@ unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool che
 | 
			
		|||
           registration above is undone. */
 | 
			
		||||
        if (checkOutputs) checkDerivationOutputs(info.path, drv);
 | 
			
		||||
 | 
			
		||||
        foreach (DerivationOutputs::iterator, i, drv.outputs) {
 | 
			
		||||
            SQLiteStmtUse use(stmtAddDerivationOutput);
 | 
			
		||||
            stmtAddDerivationOutput.bind(id);
 | 
			
		||||
            stmtAddDerivationOutput.bind(i->first);
 | 
			
		||||
            stmtAddDerivationOutput.bind(i->second.path);
 | 
			
		||||
            if (sqlite3_step(stmtAddDerivationOutput) != SQLITE_DONE)
 | 
			
		||||
                throwSQLiteError(db, format("adding derivation output for `%1%' in database") % info.path);
 | 
			
		||||
        for (auto & i : drv.outputs) {
 | 
			
		||||
            stmtAddDerivationOutput.use()
 | 
			
		||||
                (id)
 | 
			
		||||
                (i.first)
 | 
			
		||||
                (i.second.path)
 | 
			
		||||
                .exec();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -734,76 +562,52 @@ unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool che
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void LocalStore::addReference(unsigned long long referrer, unsigned long long reference)
 | 
			
		||||
void LocalStore::addReference(uint64_t referrer, uint64_t reference)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtAddReference);
 | 
			
		||||
    stmtAddReference.bind(referrer);
 | 
			
		||||
    stmtAddReference.bind(reference);
 | 
			
		||||
    if (sqlite3_step(stmtAddReference) != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(db, "adding reference to database");
 | 
			
		||||
    stmtAddReference.use()(referrer)(reference).exec();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void LocalStore::registerFailedPath(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtRegisterFailedPath);
 | 
			
		||||
        stmtRegisterFailedPath.bind(path);
 | 
			
		||||
        stmtRegisterFailedPath.bind(time(0));
 | 
			
		||||
        if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, format("registering failed path `%1%'") % path);
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    retrySQLite<void>([&]() {
 | 
			
		||||
        stmtRegisterFailedPath.use()(path)(time(0)).step();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool LocalStore::hasPathFailed(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtHasPathFailed);
 | 
			
		||||
        stmtHasPathFailed.bind(path);
 | 
			
		||||
        int res = sqlite3_step(stmtHasPathFailed);
 | 
			
		||||
        if (res != SQLITE_DONE && res != SQLITE_ROW)
 | 
			
		||||
            throwSQLiteError(db, "querying whether path failed");
 | 
			
		||||
        return res == SQLITE_ROW;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    return retrySQLite<bool>([&]() {
 | 
			
		||||
        return stmtHasPathFailed.use()(path).next();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PathSet LocalStore::queryFailedPaths()
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtQueryFailedPaths);
 | 
			
		||||
    return retrySQLite<PathSet>([&]() {
 | 
			
		||||
        auto useQueryFailedPaths(stmtQueryFailedPaths.use());
 | 
			
		||||
 | 
			
		||||
        PathSet res;
 | 
			
		||||
        int r;
 | 
			
		||||
        while ((r = sqlite3_step(stmtQueryFailedPaths)) == SQLITE_ROW) {
 | 
			
		||||
            const char * s = (const char *) sqlite3_column_text(stmtQueryFailedPaths, 0);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            res.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, "error querying failed paths");
 | 
			
		||||
        while (useQueryFailedPaths.next())
 | 
			
		||||
            res.insert(useQueryFailedPaths.getStr(0));
 | 
			
		||||
 | 
			
		||||
        return res;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void LocalStore::clearFailedPaths(const PathSet & paths)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    retrySQLite<void>([&]() {
 | 
			
		||||
        SQLiteTxn txn(db);
 | 
			
		||||
 | 
			
		||||
        foreach (PathSet::const_iterator, i, paths) {
 | 
			
		||||
            SQLiteStmtUse use(stmtClearFailedPath);
 | 
			
		||||
            stmtClearFailedPath.bind(*i);
 | 
			
		||||
            if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
 | 
			
		||||
                throwSQLiteError(db, format("clearing failed path `%1%' in database") % *i);
 | 
			
		||||
        }
 | 
			
		||||
        for (auto & path : paths)
 | 
			
		||||
            stmtClearFailedPath.use()(path).exec();
 | 
			
		||||
 | 
			
		||||
        txn.commit();
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -828,47 +632,34 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
 | 
			
		|||
 | 
			
		||||
    assertStorePath(path);
 | 
			
		||||
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    return retrySQLite<ValidPathInfo>([&]() {
 | 
			
		||||
 | 
			
		||||
        /* Get the path info. */
 | 
			
		||||
        SQLiteStmtUse use1(stmtQueryPathInfo);
 | 
			
		||||
        auto useQueryPathInfo(stmtQueryPathInfo.use()(path));
 | 
			
		||||
 | 
			
		||||
        stmtQueryPathInfo.bind(path);
 | 
			
		||||
        if (!useQueryPathInfo.next())
 | 
			
		||||
            throw Error(format("path `%1%' is not valid") % path);
 | 
			
		||||
 | 
			
		||||
        int r = sqlite3_step(stmtQueryPathInfo);
 | 
			
		||||
        if (r == SQLITE_DONE) throw Error(format("path `%1%' is not valid") % path);
 | 
			
		||||
        if (r != SQLITE_ROW) throwSQLiteError(db, "querying path in database");
 | 
			
		||||
        info.id = useQueryPathInfo.getInt(0);
 | 
			
		||||
 | 
			
		||||
        info.id = sqlite3_column_int(stmtQueryPathInfo, 0);
 | 
			
		||||
        info.hash = parseHashField(path, useQueryPathInfo.getStr(1));
 | 
			
		||||
 | 
			
		||||
        const char * s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 1);
 | 
			
		||||
        assert(s);
 | 
			
		||||
        info.hash = parseHashField(path, s);
 | 
			
		||||
        info.registrationTime = useQueryPathInfo.getInt(2);
 | 
			
		||||
 | 
			
		||||
        info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
 | 
			
		||||
 | 
			
		||||
        s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
 | 
			
		||||
        auto s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
 | 
			
		||||
        if (s) info.deriver = s;
 | 
			
		||||
 | 
			
		||||
        /* Note that narSize = NULL yields 0. */
 | 
			
		||||
        info.narSize = sqlite3_column_int64(stmtQueryPathInfo, 4);
 | 
			
		||||
        info.narSize = useQueryPathInfo.getInt(4);
 | 
			
		||||
 | 
			
		||||
        /* Get the references. */
 | 
			
		||||
        SQLiteStmtUse use2(stmtQueryReferences);
 | 
			
		||||
        auto useQueryReferences(stmtQueryReferences.use()(info.id));
 | 
			
		||||
 | 
			
		||||
        stmtQueryReferences.bind(info.id);
 | 
			
		||||
 | 
			
		||||
        while ((r = sqlite3_step(stmtQueryReferences)) == SQLITE_ROW) {
 | 
			
		||||
            s = (const char *) sqlite3_column_text(stmtQueryReferences, 0);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            info.references.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, format("error getting references of `%1%'") % path);
 | 
			
		||||
        while (useQueryReferences.next())
 | 
			
		||||
            info.references.insert(useQueryReferences.getStr(0));
 | 
			
		||||
 | 
			
		||||
        return info;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -876,78 +667,56 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
 | 
			
		|||
   narSize field. */
 | 
			
		||||
void LocalStore::updatePathInfo(const ValidPathInfo & info)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtUpdatePathInfo);
 | 
			
		||||
    if (info.narSize != 0)
 | 
			
		||||
        stmtUpdatePathInfo.bind64(info.narSize);
 | 
			
		||||
    else
 | 
			
		||||
        stmtUpdatePathInfo.bind(); // null
 | 
			
		||||
    stmtUpdatePathInfo.bind("sha256:" + printHash(info.hash));
 | 
			
		||||
    stmtUpdatePathInfo.bind(info.path);
 | 
			
		||||
    if (sqlite3_step(stmtUpdatePathInfo) != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(db, format("updating info of path `%1%' in database") % info.path);
 | 
			
		||||
    stmtUpdatePathInfo.use()
 | 
			
		||||
        (info.narSize, info.narSize != 0)
 | 
			
		||||
        ("sha256:" + printHash(info.hash))
 | 
			
		||||
        (info.path)
 | 
			
		||||
        .exec();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
unsigned long long LocalStore::queryValidPathId(const Path & path)
 | 
			
		||||
uint64_t LocalStore::queryValidPathId(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtQueryPathInfo);
 | 
			
		||||
    stmtQueryPathInfo.bind(path);
 | 
			
		||||
    int res = sqlite3_step(stmtQueryPathInfo);
 | 
			
		||||
    if (res == SQLITE_ROW) return sqlite3_column_int(stmtQueryPathInfo, 0);
 | 
			
		||||
    if (res == SQLITE_DONE) throw Error(format("path `%1%' is not valid") % path);
 | 
			
		||||
    throwSQLiteError(db, "querying path in database");
 | 
			
		||||
    auto use(stmtQueryPathInfo.use()(path));
 | 
			
		||||
    if (!use.next())
 | 
			
		||||
        throw Error(format("path ‘%1%’ is not valid") % path);
 | 
			
		||||
    return use.getInt(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool LocalStore::isValidPath_(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtQueryPathInfo);
 | 
			
		||||
    stmtQueryPathInfo.bind(path);
 | 
			
		||||
    int res = sqlite3_step(stmtQueryPathInfo);
 | 
			
		||||
    if (res != SQLITE_DONE && res != SQLITE_ROW)
 | 
			
		||||
        throwSQLiteError(db, "querying path in database");
 | 
			
		||||
    return res == SQLITE_ROW;
 | 
			
		||||
    return stmtQueryPathInfo.use()(path).next();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool LocalStore::isValidPath(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    return retrySQLite<bool>([&]() {
 | 
			
		||||
        return isValidPath_(path);
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PathSet LocalStore::queryValidPaths(const PathSet & paths)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    return retrySQLite<PathSet>([&]() {
 | 
			
		||||
        PathSet res;
 | 
			
		||||
        foreach (PathSet::const_iterator, i, paths)
 | 
			
		||||
            if (isValidPath_(*i)) res.insert(*i);
 | 
			
		||||
        return res;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PathSet LocalStore::queryAllValidPaths()
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmt stmt;
 | 
			
		||||
        stmt.create(db, "select path from ValidPaths");
 | 
			
		||||
 | 
			
		||||
    return retrySQLite<PathSet>([&]() {
 | 
			
		||||
        auto use(stmtQueryValidPaths.use());
 | 
			
		||||
        PathSet res;
 | 
			
		||||
        int r;
 | 
			
		||||
        while ((r = sqlite3_step(stmt)) == SQLITE_ROW) {
 | 
			
		||||
            const char * s = (const char *) sqlite3_column_text(stmt, 0);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            res.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, "error getting valid paths");
 | 
			
		||||
 | 
			
		||||
        while (use.next()) res.insert(use.getStr(0));
 | 
			
		||||
        return res;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -961,28 +730,19 @@ void LocalStore::queryReferences(const Path & path,
 | 
			
		|||
 | 
			
		||||
void LocalStore::queryReferrers_(const Path & path, PathSet & referrers)
 | 
			
		||||
{
 | 
			
		||||
    SQLiteStmtUse use(stmtQueryReferrers);
 | 
			
		||||
    auto useQueryReferrers(stmtQueryReferrers.use()(path));
 | 
			
		||||
 | 
			
		||||
    stmtQueryReferrers.bind(path);
 | 
			
		||||
 | 
			
		||||
    int r;
 | 
			
		||||
    while ((r = sqlite3_step(stmtQueryReferrers)) == SQLITE_ROW) {
 | 
			
		||||
        const char * s = (const char *) sqlite3_column_text(stmtQueryReferrers, 0);
 | 
			
		||||
        assert(s);
 | 
			
		||||
        referrers.insert(s);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (r != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(db, format("error getting references of `%1%'") % path);
 | 
			
		||||
    while (useQueryReferrers.next())
 | 
			
		||||
        referrers.insert(useQueryReferrers.getStr(0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
 | 
			
		||||
{
 | 
			
		||||
    assertStorePath(path);
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    return retrySQLite<void>([&]() {
 | 
			
		||||
        queryReferrers_(path, referrers);
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -996,67 +756,43 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
 | 
			
		|||
{
 | 
			
		||||
    assertStorePath(path);
 | 
			
		||||
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtQueryValidDerivers);
 | 
			
		||||
        stmtQueryValidDerivers.bind(path);
 | 
			
		||||
    return retrySQLite<PathSet>([&]() {
 | 
			
		||||
        auto useQueryValidDerivers(stmtQueryValidDerivers.use()(path));
 | 
			
		||||
 | 
			
		||||
        PathSet derivers;
 | 
			
		||||
        int r;
 | 
			
		||||
        while ((r = sqlite3_step(stmtQueryValidDerivers)) == SQLITE_ROW) {
 | 
			
		||||
            const char * s = (const char *) sqlite3_column_text(stmtQueryValidDerivers, 1);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            derivers.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, format("error getting valid derivers of `%1%'") % path);
 | 
			
		||||
        while (useQueryValidDerivers.next())
 | 
			
		||||
            derivers.insert(useQueryValidDerivers.getStr(1));
 | 
			
		||||
 | 
			
		||||
        return derivers;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PathSet LocalStore::queryDerivationOutputs(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtQueryDerivationOutputs);
 | 
			
		||||
        stmtQueryDerivationOutputs.bind(queryValidPathId(path));
 | 
			
		||||
    return retrySQLite<PathSet>([&]() {
 | 
			
		||||
        auto useQueryDerivationOutputs(stmtQueryDerivationOutputs.use()(queryValidPathId(path)));
 | 
			
		||||
 | 
			
		||||
        PathSet outputs;
 | 
			
		||||
        int r;
 | 
			
		||||
        while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
 | 
			
		||||
            const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 1);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            outputs.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, format("error getting outputs of `%1%'") % path);
 | 
			
		||||
        while (useQueryDerivationOutputs.next())
 | 
			
		||||
            outputs.insert(useQueryDerivationOutputs.getStr(1));
 | 
			
		||||
 | 
			
		||||
        return outputs;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
StringSet LocalStore::queryDerivationOutputNames(const Path & path)
 | 
			
		||||
{
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtQueryDerivationOutputs);
 | 
			
		||||
        stmtQueryDerivationOutputs.bind(queryValidPathId(path));
 | 
			
		||||
    return retrySQLite<StringSet>([&]() {
 | 
			
		||||
        auto useQueryDerivationOutputs(stmtQueryDerivationOutputs.use()(queryValidPathId(path)));
 | 
			
		||||
 | 
			
		||||
        StringSet outputNames;
 | 
			
		||||
        int r;
 | 
			
		||||
        while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
 | 
			
		||||
            const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0);
 | 
			
		||||
            assert(s);
 | 
			
		||||
            outputNames.insert(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (r != SQLITE_DONE)
 | 
			
		||||
            throwSQLiteError(db, format("error getting output names of `%1%'") % path);
 | 
			
		||||
        while (useQueryDerivationOutputs.next())
 | 
			
		||||
            outputNames.insert(useQueryDerivationOutputs.getStr(0));
 | 
			
		||||
 | 
			
		||||
        return outputNames;
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1066,17 +802,14 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
 | 
			
		|||
 | 
			
		||||
    Path prefix = settings.nixStore + "/" + hashPart;
 | 
			
		||||
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
        SQLiteStmtUse use(stmtQueryPathFromHashPart);
 | 
			
		||||
        stmtQueryPathFromHashPart.bind(prefix);
 | 
			
		||||
    return retrySQLite<Path>([&]() -> Path {
 | 
			
		||||
        auto useQueryPathFromHashPart(stmtQueryPathFromHashPart.use()(prefix));
 | 
			
		||||
 | 
			
		||||
        int res = sqlite3_step(stmtQueryPathFromHashPart);
 | 
			
		||||
        if (res == SQLITE_DONE) return "";
 | 
			
		||||
        if (res != SQLITE_ROW) throwSQLiteError(db, "finding path in database");
 | 
			
		||||
        if (!useQueryPathFromHashPart.next()) return "";
 | 
			
		||||
 | 
			
		||||
        const char * s = (const char *) sqlite3_column_text(stmtQueryPathFromHashPart, 0);
 | 
			
		||||
        return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : "";
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1306,7 +1039,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
 | 
			
		|||
     * expense of some speed of the path registering operation. */
 | 
			
		||||
    if (settings.syncBeforeRegistering) sync();
 | 
			
		||||
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    return retrySQLite<void>([&]() {
 | 
			
		||||
        SQLiteTxn txn(db);
 | 
			
		||||
        PathSet paths;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1319,10 +1052,10 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
 | 
			
		|||
            paths.insert(i->path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (ValidPathInfos::const_iterator, i, infos) {
 | 
			
		||||
            unsigned long long referrer = queryValidPathId(i->path);
 | 
			
		||||
            foreach (PathSet::iterator, j, i->references)
 | 
			
		||||
                addReference(referrer, queryValidPathId(*j));
 | 
			
		||||
        for (auto & i : infos) {
 | 
			
		||||
            auto referrer = queryValidPathId(i.path);
 | 
			
		||||
            for (auto & j : i.references)
 | 
			
		||||
                addReference(referrer, queryValidPathId(j));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Check that the derivation outputs are correct.  We can't do
 | 
			
		||||
| 
						 | 
				
			
			@ -1343,7 +1076,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
 | 
			
		|||
        topoSortPaths(*this, paths);
 | 
			
		||||
 | 
			
		||||
        txn.commit();
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1355,12 +1088,7 @@ void LocalStore::invalidatePath(const Path & path)
 | 
			
		|||
 | 
			
		||||
    drvHashes.erase(path);
 | 
			
		||||
 | 
			
		||||
    SQLiteStmtUse use(stmtInvalidatePath);
 | 
			
		||||
 | 
			
		||||
    stmtInvalidatePath.bind(path);
 | 
			
		||||
 | 
			
		||||
    if (sqlite3_step(stmtInvalidatePath) != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(db, format("invalidating path `%1%' in database") % path);
 | 
			
		||||
    stmtInvalidatePath.use()(path).exec();
 | 
			
		||||
 | 
			
		||||
    /* Note that the foreign key constraints on the Refs table take
 | 
			
		||||
       care of deleting the references entries for `path'. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1733,7 +1461,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
 | 
			
		|||
{
 | 
			
		||||
    assertStorePath(path);
 | 
			
		||||
 | 
			
		||||
    retry_sqlite {
 | 
			
		||||
    retrySQLite<void>([&]() {
 | 
			
		||||
        SQLiteTxn txn(db);
 | 
			
		||||
 | 
			
		||||
        if (isValidPath_(path)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1746,7 +1474,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        txn.commit();
 | 
			
		||||
    } end_retry_sqlite;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,12 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "sqlite.hh"
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
#include "pathlocks.hh"
 | 
			
		||||
#include "store-api.hh"
 | 
			
		||||
#include "util.hh"
 | 
			
		||||
#include "pathlocks.hh"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class sqlite3;
 | 
			
		||||
class sqlite3_stmt;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace nix {
 | 
			
		||||
| 
						 | 
				
			
			@ -52,34 +49,6 @@ struct RunningSubstituter
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Wrapper object to close the SQLite database automatically. */
 | 
			
		||||
struct SQLite
 | 
			
		||||
{
 | 
			
		||||
    sqlite3 * db;
 | 
			
		||||
    SQLite() { db = 0; }
 | 
			
		||||
    ~SQLite();
 | 
			
		||||
    operator sqlite3 * () { return db; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Wrapper object to create and destroy SQLite prepared statements. */
 | 
			
		||||
struct SQLiteStmt
 | 
			
		||||
{
 | 
			
		||||
    sqlite3 * db;
 | 
			
		||||
    sqlite3_stmt * stmt;
 | 
			
		||||
    unsigned int curArg;
 | 
			
		||||
    SQLiteStmt() { stmt = 0; }
 | 
			
		||||
    void create(sqlite3 * db, const string & s);
 | 
			
		||||
    void reset();
 | 
			
		||||
    ~SQLiteStmt();
 | 
			
		||||
    operator sqlite3_stmt * () { return stmt; }
 | 
			
		||||
    void bind(const string & value);
 | 
			
		||||
    void bind(int value);
 | 
			
		||||
    void bind64(long long value);
 | 
			
		||||
    void bind();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LocalStore : public StoreAPI
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -238,6 +207,7 @@ private:
 | 
			
		|||
    SQLiteStmt stmtQueryValidDerivers;
 | 
			
		||||
    SQLiteStmt stmtQueryDerivationOutputs;
 | 
			
		||||
    SQLiteStmt stmtQueryPathFromHashPart;
 | 
			
		||||
    SQLiteStmt stmtQueryValidPaths;
 | 
			
		||||
 | 
			
		||||
    /* Cache for pathContentsGood(). */
 | 
			
		||||
    std::map<Path, bool> pathContentsGoodCache;
 | 
			
		||||
| 
						 | 
				
			
			@ -254,11 +224,11 @@ private:
 | 
			
		|||
 | 
			
		||||
    void makeStoreWritable();
 | 
			
		||||
 | 
			
		||||
    unsigned long long queryValidPathId(const Path & path);
 | 
			
		||||
    uint64_t queryValidPathId(const Path & path);
 | 
			
		||||
 | 
			
		||||
    unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
 | 
			
		||||
    uint64_t addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
 | 
			
		||||
 | 
			
		||||
    void addReference(unsigned long long referrer, unsigned long long reference);
 | 
			
		||||
    void addReference(uint64_t referrer, uint64_t reference);
 | 
			
		||||
 | 
			
		||||
    void appendReferrer(const Path & from, const Path & to, bool lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -148,10 +148,23 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
 | 
			
		|||
            inodeHash.insert(st.st_ino);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (errno != EEXIST)
 | 
			
		||||
 | 
			
		||||
	switch (errno) {
 | 
			
		||||
	case EEXIST:
 | 
			
		||||
	    /* Fall through if another process created ‘linkPath’ before
 | 
			
		||||
	       we did. */
 | 
			
		||||
	    break;
 | 
			
		||||
 | 
			
		||||
	case ENOSPC:
 | 
			
		||||
	    /* On ext4, that probably means the directory index is full.  When
 | 
			
		||||
	       that happens, it's fine to ignore it: we just effectively
 | 
			
		||||
	       disable deduplication of this file.  */
 | 
			
		||||
	    printMsg(lvlInfo, format("cannot link `%1%' to `%2%': %m") % linkPath % path);
 | 
			
		||||
	    return;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
            throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path);
 | 
			
		||||
        /* Fall through if another process created ‘linkPath’ before
 | 
			
		||||
           we did. */
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Yes!  We've seen a file with the same contents.  Replace the
 | 
			
		||||
| 
						 | 
				
			
			@ -195,8 +208,8 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
 | 
			
		|||
                printMsg(lvlInfo, format("`%1%' has maximum number of links") % linkPath);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        throw SysError(format("cannot link `%1%' to `%2%'") % tempLink % linkPath);
 | 
			
		||||
    }
 | 
			
		||||
	    throw SysError(format("cannot link `%1%' to `%2%'") % tempLink % linkPath);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /* Atomically replace the old file with the new hard link. */
 | 
			
		||||
    if (rename(tempLink.c_str(), path.c_str()) == -1) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										166
									
								
								nix/libstore/sqlite.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								nix/libstore/sqlite.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,166 @@
 | 
			
		|||
#include "sqlite.hh"
 | 
			
		||||
#include "util.hh"
 | 
			
		||||
 | 
			
		||||
#include <sqlite3.h>
 | 
			
		||||
 | 
			
		||||
namespace nix {
 | 
			
		||||
 | 
			
		||||
[[noreturn]] void throwSQLiteError(sqlite3 * db, const format & f)
 | 
			
		||||
{
 | 
			
		||||
    int err = sqlite3_errcode(db);
 | 
			
		||||
    if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) {
 | 
			
		||||
        if (err == SQLITE_PROTOCOL)
 | 
			
		||||
            printMsg(lvlError, "warning: SQLite database is busy (SQLITE_PROTOCOL)");
 | 
			
		||||
        else {
 | 
			
		||||
            static bool warned = false;
 | 
			
		||||
            if (!warned) {
 | 
			
		||||
                printMsg(lvlError, "warning: SQLite database is busy");
 | 
			
		||||
                warned = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        /* Sleep for a while since retrying the transaction right away
 | 
			
		||||
           is likely to fail again. */
 | 
			
		||||
#if HAVE_NANOSLEEP
 | 
			
		||||
        struct timespec t;
 | 
			
		||||
        t.tv_sec = 0;
 | 
			
		||||
        t.tv_nsec = (random() % 100) * 1000 * 1000; /* <= 0.1s */
 | 
			
		||||
        nanosleep(&t, 0);
 | 
			
		||||
#else
 | 
			
		||||
        sleep(1);
 | 
			
		||||
#endif
 | 
			
		||||
        throw SQLiteBusy(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLite::~SQLite()
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        if (db && sqlite3_close(db) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "closing database");
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        ignoreException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::create(sqlite3 * db, const string & s)
 | 
			
		||||
{
 | 
			
		||||
    checkInterrupt();
 | 
			
		||||
    assert(!stmt);
 | 
			
		||||
    if (sqlite3_prepare_v2(db, s.c_str(), -1, &stmt, 0) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "creating statement");
 | 
			
		||||
    this->db = db;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::~SQLiteStmt()
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        if (stmt && sqlite3_finalize(stmt) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "finalizing statement");
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        ignoreException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::Use::Use(SQLiteStmt & stmt)
 | 
			
		||||
    : stmt(stmt)
 | 
			
		||||
{
 | 
			
		||||
    assert(stmt.stmt);
 | 
			
		||||
    /* Note: sqlite3_reset() returns the error code for the most
 | 
			
		||||
       recent call to sqlite3_step().  So ignore it. */
 | 
			
		||||
    sqlite3_reset(stmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::Use::~Use()
 | 
			
		||||
{
 | 
			
		||||
    sqlite3_reset(stmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::Use & SQLiteStmt::Use::operator () (const std::string & value, bool notNull)
 | 
			
		||||
{
 | 
			
		||||
    if (notNull) {
 | 
			
		||||
        if (sqlite3_bind_text(stmt, curArg++, value.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(stmt.db, "binding argument");
 | 
			
		||||
    } else
 | 
			
		||||
        bind();
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::Use & SQLiteStmt::Use::operator () (int64_t value, bool notNull)
 | 
			
		||||
{
 | 
			
		||||
    if (notNull) {
 | 
			
		||||
        if (sqlite3_bind_int64(stmt, curArg++, value) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(stmt.db, "binding argument");
 | 
			
		||||
    } else
 | 
			
		||||
        bind();
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteStmt::Use & SQLiteStmt::Use::bind()
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_bind_null(stmt, curArg++) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(stmt.db, "binding argument");
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SQLiteStmt::Use::step()
 | 
			
		||||
{
 | 
			
		||||
    return sqlite3_step(stmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SQLiteStmt::Use::exec()
 | 
			
		||||
{
 | 
			
		||||
    int r = step();
 | 
			
		||||
    assert(r != SQLITE_ROW);
 | 
			
		||||
    if (r != SQLITE_DONE)
 | 
			
		||||
        throwSQLiteError(stmt.db, "executing SQLite statement");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SQLiteStmt::Use::next()
 | 
			
		||||
{
 | 
			
		||||
    int r = step();
 | 
			
		||||
    if (r != SQLITE_DONE && r != SQLITE_ROW)
 | 
			
		||||
        throwSQLiteError(stmt.db, "executing SQLite query");
 | 
			
		||||
    return r == SQLITE_ROW;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string SQLiteStmt::Use::getStr(int col)
 | 
			
		||||
{
 | 
			
		||||
    auto s = (const char *) sqlite3_column_text(stmt, col);
 | 
			
		||||
    assert(s);
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SQLiteStmt::Use::getInt(int col)
 | 
			
		||||
{
 | 
			
		||||
    // FIXME: detect nulls?
 | 
			
		||||
    return sqlite3_column_int64(stmt, col);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteTxn::SQLiteTxn(sqlite3 * db)
 | 
			
		||||
{
 | 
			
		||||
    this->db = db;
 | 
			
		||||
    if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "starting transaction");
 | 
			
		||||
    active = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SQLiteTxn::commit()
 | 
			
		||||
{
 | 
			
		||||
    if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
        throwSQLiteError(db, "committing transaction");
 | 
			
		||||
    active = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SQLiteTxn::~SQLiteTxn()
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        if (active && sqlite3_exec(db, "rollback;", 0, 0, 0) != SQLITE_OK)
 | 
			
		||||
            throwSQLiteError(db, "aborting transaction");
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
        ignoreException();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								nix/libstore/sqlite.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								nix/libstore/sqlite.hh
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,102 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "types.hh"
 | 
			
		||||
 | 
			
		||||
class sqlite3;
 | 
			
		||||
class sqlite3_stmt;
 | 
			
		||||
 | 
			
		||||
namespace nix {
 | 
			
		||||
 | 
			
		||||
/* RAII wrapper to close a SQLite database automatically. */
 | 
			
		||||
struct SQLite
 | 
			
		||||
{
 | 
			
		||||
    sqlite3 * db;
 | 
			
		||||
    SQLite() { db = 0; }
 | 
			
		||||
    ~SQLite();
 | 
			
		||||
    operator sqlite3 * () { return db; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* RAII wrapper to create and destroy SQLite prepared statements. */
 | 
			
		||||
struct SQLiteStmt
 | 
			
		||||
{
 | 
			
		||||
    sqlite3 * db = 0;
 | 
			
		||||
    sqlite3_stmt * stmt = 0;
 | 
			
		||||
    SQLiteStmt() { }
 | 
			
		||||
    void create(sqlite3 * db, const std::string & s);
 | 
			
		||||
    ~SQLiteStmt();
 | 
			
		||||
    operator sqlite3_stmt * () { return stmt; }
 | 
			
		||||
 | 
			
		||||
    /* Helper for binding / executing statements. */
 | 
			
		||||
    class Use
 | 
			
		||||
    {
 | 
			
		||||
        friend struct SQLiteStmt;
 | 
			
		||||
    private:
 | 
			
		||||
        SQLiteStmt & stmt;
 | 
			
		||||
        unsigned int curArg = 1;
 | 
			
		||||
        Use(SQLiteStmt & stmt);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        ~Use();
 | 
			
		||||
 | 
			
		||||
        /* Bind the next parameter. */
 | 
			
		||||
        Use & operator () (const std::string & value, bool notNull = true);
 | 
			
		||||
        Use & operator () (int64_t value, bool notNull = true);
 | 
			
		||||
        Use & bind(); // null
 | 
			
		||||
 | 
			
		||||
        int step();
 | 
			
		||||
 | 
			
		||||
        /* Execute a statement that does not return rows. */
 | 
			
		||||
        void exec();
 | 
			
		||||
 | 
			
		||||
        /* For statements that return 0 or more rows. Returns true iff
 | 
			
		||||
           a row is available. */
 | 
			
		||||
        bool next();
 | 
			
		||||
 | 
			
		||||
        std::string getStr(int col);
 | 
			
		||||
        int64_t getInt(int col);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Use use()
 | 
			
		||||
    {
 | 
			
		||||
        return Use(*this);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* RAII helper that ensures transactions are aborted unless explicitly
 | 
			
		||||
   committed. */
 | 
			
		||||
struct SQLiteTxn
 | 
			
		||||
{
 | 
			
		||||
    bool active = false;
 | 
			
		||||
    sqlite3 * db;
 | 
			
		||||
 | 
			
		||||
    SQLiteTxn(sqlite3 * db);
 | 
			
		||||
 | 
			
		||||
    void commit();
 | 
			
		||||
 | 
			
		||||
    ~SQLiteTxn();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MakeError(SQLiteError, Error);
 | 
			
		||||
MakeError(SQLiteBusy, SQLiteError);
 | 
			
		||||
 | 
			
		||||
[[noreturn]] void throwSQLiteError(sqlite3 * db, const format & f);
 | 
			
		||||
 | 
			
		||||
/* Convenience function for retrying a SQLite transaction when the
 | 
			
		||||
   database is busy. */
 | 
			
		||||
template<typename T>
 | 
			
		||||
T retrySQLite(std::function<T()> fun)
 | 
			
		||||
{
 | 
			
		||||
    while (true) {
 | 
			
		||||
        try {
 | 
			
		||||
            return fun();
 | 
			
		||||
        } catch (SQLiteBusy & e) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +89,8 @@ struct ValidPathInfo
 | 
			
		|||
    Hash hash;
 | 
			
		||||
    PathSet references;
 | 
			
		||||
    time_t registrationTime = 0;
 | 
			
		||||
    unsigned long long narSize = 0; // 0 = unknown
 | 
			
		||||
    unsigned long long id; // internal use only
 | 
			
		||||
    uint64_t narSize = 0; // 0 = unknown
 | 
			
		||||
    uint64_t id; // internal use only
 | 
			
		||||
 | 
			
		||||
    bool operator == (const ValidPathInfo & i) const
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,7 +86,8 @@ libstore_a_SOURCES =				\
 | 
			
		|||
  %D%/libstore/local-store.cc			\
 | 
			
		||||
  %D%/libstore/build.cc				\
 | 
			
		||||
  %D%/libstore/pathlocks.cc			\
 | 
			
		||||
  %D%/libstore/derivations.cc
 | 
			
		||||
  %D%/libstore/derivations.cc			\
 | 
			
		||||
  %D%/libstore/sqlite.cc
 | 
			
		||||
 | 
			
		||||
libstore_headers =				\
 | 
			
		||||
  %D%/libstore/references.hh			\
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +97,7 @@ libstore_headers =				\
 | 
			
		|||
  %D%/libstore/derivations.hh			\
 | 
			
		||||
  %D%/libstore/misc.hh				\
 | 
			
		||||
  %D%/libstore/local-store.hh			\
 | 
			
		||||
  %D%/libstore/sqlite.hh			\
 | 
			
		||||
  %D%/libstore/store-api.hh
 | 
			
		||||
 | 
			
		||||
libstore_a_CPPFLAGS =				\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
# GNU Guix --- Functional package management for GNU
 | 
			
		||||
# Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
 | 
			
		||||
# Copyright © 2013, 2014, 2016 Ludovic Courtès <ludo@gnu.org>
 | 
			
		||||
# Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
 | 
			
		||||
#
 | 
			
		||||
# This file is part of GNU Guix.
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +27,7 @@ tmpdir="guix-hash-$$"
 | 
			
		|||
trap 'rm -rf "$tmpdir"' EXIT
 | 
			
		||||
 | 
			
		||||
test `guix hash /dev/null` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
 | 
			
		||||
test `echo -n | guix hash -` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
 | 
			
		||||
test `guix hash -f nix-base32 /dev/null` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
 | 
			
		||||
test `guix hash -f hex /dev/null` = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
 | 
			
		||||
test `guix hash -f base32 /dev/null` = 4oymiquy7qobjgx36tejs35zeqt24qpemsnzgtfeswmrw6csxbkq
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in a new issue