all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: swedebugia <swedebugia@riseup.net>
To: "Jakob L. Kreuze" <zerodaysfordays@sdf.lonestar.org>
Cc: guix-devel@gnu.org
Subject: Re: Go importer - help with git-fetch
Date: Tue, 6 Aug 2019 22:26:46 +0200	[thread overview]
Message-ID: <7ff3ff2d-0e35-8b57-8b0c-28e0ccfda326@riseup.net> (raw)
In-Reply-To: <8736iezbr1.fsf@sdf.lonestar.org>

[-- Attachment #1: Type: text/plain, Size: 630 bytes --]

Hi :)

Thanks for the quick responses.

On 2019-08-06 15:04, Jakob L. Kreuze wrote:
> Ricardo Wurmus <rekado@elephly.net> writes:
>
> ...
> Yes -- my apologies, I probably should have clarified in the earlier
> email thread. 'git-fetch' from (guix git-download) needs to be run in
> the store monad, but 'git-fetch' from (guix build git) doesn't. You can
> get rid of 'with-store' and 'run-with-store'.

Done! (see attached)

I got the git-fetch and hashing to work. :D

Next challenge: silence git-fetch. Do any of you know how to do that? I 
imagine it entails sending its text output to some dummy port.

-- 
Cheers Swedebugia

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-guix-import-Add-golang-importer-utilizing-the-Go-sea.patch --]
[-- Type: text/x-patch; name="0001-guix-import-Add-golang-importer-utilizing-the-Go-sea.patch", Size: 15621 bytes --]

From f01dff653c365fb15acdac165a3ad0cf2f809930 Mon Sep 17 00:00:00 2001
From: swedebugia <swedebugia@riseup.net>
Date: Tue, 6 Aug 2019 22:20:10 +0200
Subject: [PATCH] guix: import: Add golang importer utilizing the Go-search
 API.

* guix/import/github.scm (fetch-readme, fetch-license)
  (fetch-latest-commit, headers, http-url?): Add support for /commits,
  /license, and /readme Github APIv3 endpoints.
  (export): Export fetch-readme, fetch-license & fetch-latest-commit.
  (github-user-slash-repository): Use http-url? for better error reporting.
* guix/import/go.scm: New file.
* guix/import/utils.scm (guix-hash-directory): New procedure.
  (export): Export it.
---
 guix/import/github.scm |  66 ++++++++++--
 guix/import/go.scm     | 232 +++++++++++++++++++++++++++++++++++++++++
 guix/import/utils.scm  |   5 +
 3 files changed, 293 insertions(+), 10 deletions(-)
 create mode 100644 guix/import/go.scm

diff --git a/guix/import/github.scm b/guix/import/github.scm
index fa23fa4c0..b889da69a 100644
--- a/guix/import/github.scm
+++ b/guix/import/github.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2018 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2019 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2019 swedebugia <swedebugia@riseup.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -33,7 +34,11 @@
   #:use-module (guix upstream)
   #:use-module (guix http-client)
   #:use-module (web uri)
-  #:export (%github-updater))
+  #:export (%github-updater
+            fetch-latest-commit
+            fetch-license
+            latest-released-version
+            fetch-readme))
 
 (define (find-extension url)
   "Return the extension of the archive e.g. '.tar.gz' given a URL, or
@@ -115,19 +120,66 @@ URL of the form 'https://github.com/arq5x/bedtools2/archive/v2.24.0.tar.gz'"
     ((_ owner project . rest)
      (string-append (basename project ".git")))))
 
+(define (http-url? url)
+  ;; We only support Github urls beginning with http.
+  (string-prefix? "http" url))
+
 (define (github-user-slash-repository url)
   "Return a string e.g. arq5x/bedtools2 of the owner and the name of the
 repository separated by a forward slash, from a string URL of the form
 'https://github.com/arq5x/bedtools2/archive/v2.24.0.tar.gz'"
-  (match (string-split (uri-path (string->uri url)) #\/)
-    ((_ owner project . rest)
-     (string-append owner "/" (basename project ".git")))))
+  (if (http-url? url)
+   (match (string-split (uri-path (string->uri url)) #\/)
+     ((_ owner project . rest)
+      (string-append owner "/" (basename project ".git"))))
+   (error "Not a valid url.")))
 
 (define %github-token
   ;; Token to be passed to Github.com to avoid the 60-request per hour
   ;; limit, or #f.
   (make-parameter (getenv "GUIX_GITHUB_TOKEN")))
 
+(define headers
+    ;; Ask for version 3 of the API as suggested at
+    ;; <https://developer.github.com/v3/>.
+    `((Accept . "application/vnd.github.v3+json")
+      (user-agent . "GNU Guile")))
+
+(define (fetch-readme url)
+  "Return a file with the README if any from a github repository url."
+  (let ((readme-url
+         (string-append "https://api.github.com/repos/"
+                        (github-user-slash-repository url)
+                        "/readme")))
+    "Get json, extract and fetch the raw url."
+    (let ((data (json-fetch readme-url #:headers headers)))
+      (http-fetch (assoc-ref data "download_url")))))
+
+(define (fetch-license url)
+  "Return the license json if any from a github repository url. This contains
+the SPDX id among other things."
+  (let ((license-url
+         (string-append "https://api.github.com/repos/"
+                        (github-user-slash-repository url)
+                        "/license")))
+    (json-fetch license-url #:headers headers)))
+
+(define (fetch-latest-commit url)
+  "Get the latest commit-id."
+  (let ((commit-url
+         (string-append "https://api.github.com/repos/"
+                        (github-user-slash-repository url)
+                        "/commits")))
+    ;; This might be able to implement using only match
+    (assoc-ref
+     (match (vector->list (json-fetch commit-url))
+       (()                                ;empty
+        (error "No commits"))
+       ;; Pick the latest one
+       (((_ . x) . _) x)
+       )
+     "sha")))
+
 (define (fetch-releases-or-tags url)
   "Fetch the list of \"releases\" or, if it's empty, the list of tags for the
 repository at URL.  Return the corresponding JSON dictionaries (alists),
@@ -149,12 +201,6 @@ empty list."
                    (github-user-slash-repository url)
                    "/tags"))
 
-  (define headers
-    ;; Ask for version 3 of the API as suggested at
-    ;; <https://developer.github.com/v3/>.
-    `((Accept . "application/vnd.github.v3+json")
-      (user-agent . "GNU Guile")))
-
   (define (decorate url)
     (if (%github-token)
         (string-append url "?access_token=" (%github-token))
diff --git a/guix/import/go.scm b/guix/import/go.scm
new file mode 100644
index 000000000..77711fb49
--- /dev/null
+++ b/guix/import/go.scm
@@ -0,0 +1,232 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 swedebugia <swedebugia@riseup.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix 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 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix 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 GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import go)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 textual-ports)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2) ;and-let
+  #:use-module (guix utils)
+  #:use-module (guix build git)
+  #:use-module (guix import github)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module (guix packages)
+  #:use-module (web uri))
+
+;;; Commentary:
+;;; This utilizes the https://go-search.org/infoapi API.
+;;; This API contains no licenses or versions. We fetch those from github when
+;;; possible.
+
+;;; Code:
+
+(define (go-name->url name)
+  "Takes a go-name on the form github.com/andyleap/go-ssb and turns it into
+https://github.com/andyleap/go-ssb"
+  (string-append "https://" name))
+
+;; from opam.scm - should probably be factored out to utils.scm
+(define (substitute-char str what with)
+  (string-join (string-split str what) with))
+
+(define (go-name->guix-name name)
+  "Takes a go-name e.g. on the form github.com/x/y and turns it into
+go-github-com-x-y"
+  (substitute-char
+   (substitute-char
+    (cond
+     ;;((equal? name "ocamlfind") "ocaml-findlib")
+     ;;((string-prefix? "ocaml" name) name)
+     ((string-prefix? "github.com/" name) (string-append "go-github-com-" (substring name 11)))
+     ((string-prefix? "golang.org/x/" name) (string-append "go-golang-org-" (substring name 11)))
+     ((string-prefix? "cryptoscope.co/go/" name) (string-append "go-cryptoscope-co-" (substring name 11)))
+     (else (string-append "go-" name)))
+    #\_ "-")
+   #\/ "-"))
+;;(display (go-name->guix-name "golang.org/x/text/transform"))
+
+(define (fetch-data name)
+  "Fetches data about imports and description"
+  (json-fetch (string-append "https://go-search.org/api"
+                             "?action=package&id=" name)))
+;;(display (hash-table->alist (fetch-data "golang.org/x/text/transform")))
+
+(define (synopsis name)
+  (and-let* ((data (fetch-data name)))
+    (if (assoc-ref data "Synopsis")
+        (assoc-ref data "Synopsis")
+        ;; If synopsis is empty get the description instead
+        (assoc-ref data "Description"))))
+
+;;(display (synopsis "golang.org/x/text/transform"))
+
+;; Github projects enable us to get the license and readme
+(define (github-url? url)
+  (->bool (string-prefix? "https://github.com/" url)))
+
+(define (string->license name)
+  "Get SPDX-id from github if github-url"
+  (and-let* ((url (go-name->url name))
+            (github-url? url)
+            (data (fetch-license url))
+            (hasht (assoc-ref data "license"))
+            (str (string-downcase (assoc-ref hasht "spdx_id"))))
+    (cond
+     ((equal? str "gpl-3.0") '(license:gpl-3))
+     (else `(,string-append "license:" ,str)))))
+
+;;(display (string->license "github.com/andyleap/go-ssb"))
+
+(define (readme name)
+  "We get the first 1000 characters for the description"
+  (and-let* ((url (go-name->url name))
+            (github-url? url))
+    (get-string-n (fetch-readme url) 1000)))
+
+(define (description name)
+  (and-let* ((data (fetch-data name)))
+    (if (assoc-ref data "Synopsis")
+        ;; Synopsis is non-empty.
+        (if (assoc-ref data "Description")
+            (assoc-ref data "Description")
+            ;; Description is empty
+            (readme name))
+        ;; Synopsis is empty and the description from GSAPI has been used as
+        ;; synopsis, get the readme instead
+        (readme name))))
+
+;;(display (description "golang.org/x/text/transform"))
+
+;; Versions are tricky because the go-ecosystem does not rely on them at
+;; all. We get the latest released or tagged version from github and fall
+;; backto the latest commit.
+(define (version name)
+  "Get the latest release or tag if any."
+  (and-let* ((url (go-name->url name))
+             (github-url? url))
+    (latest-released-version url name)))
+
+;;(display (version "github.com/andyleap/go-ssb"))
+
+(define (commit name)
+  "Get latest commit-id"
+  (and-let* ((url (go-name->url name))
+             (github-url? url))
+    (fetch-latest-commit url)))
+
+;;(display (commit "github.com/andyleap/go-ssb"))
+
+(define (dependencies name)
+  (and-let* ((data (fetch-data name)))
+    ;; Join with (assoc-ref data "TestImports")?
+    (assoc-ref data "Imports")))
+
+;;(display (dependencies "golang.org/x/text/transform"))
+
+(define (test-dependencies name)
+  (and-let* ((data (fetch-data name)))
+    ;; Join with (assoc-ref data "TestImports")?
+    (assoc-ref data "TestImports")))
+
+;; this is from ocaml.scm
+(define (dependencies->inputs dependencies)
+  "Transform the list of dependencies in a list of inputs."
+  (if (not dependencies)
+    '()
+    (map (lambda (input)
+           (list input (list 'unquote (string->symbol input))))
+         (map go-name->guix-name dependencies))))
+
+;;(display (dependencies->inputs (dependencies "github.com/andyleap/go-ssb")))
+
+(define (go->guix-package name)
+  (let ((version (version name)))
+    (if (equal? version #t)
+        ;; Got release or tag
+        (let ((source-url (go-name->url name))
+              (commit version)
+              (inputs (dependencies->inputs (dependencies name)))
+              (synopsis (synopsis name))
+              (description (description name)))
+          ;; This is broken because of git-fetch from git-download does not at
+          ;; all work like the similar url-fetch-procedure.
+          (call-with-temporary-directory
+           (lambda (temp)
+             (and (git-fetch source-url commit temp)
+                  `(package
+                     (name ,(go-name->guix-name name))
+                     (version ,version)
+                     (source
+                      (origin
+                        (method git-fetch)
+                        (uri (git-reference
+                              (url ,source-url)
+                              (commit ,commit)))
+                        (file-name (git-file-name name version))
+                        (sha256 (base32 ,(guix-hash-directory temp)))))
+                     (build-system go-build-system)
+                     ,@(if (null? inputs)
+                           '()
+                           `((inputs ,(list 'quasiquote inputs))))
+                     (home-page ,source-url)
+                     (synopsis ,synopsis)
+                     (description ,description)
+                     (license ,@(string->license name)))))))
+        ;; No release or tag, fall back to latest commit
+        (let ((source-url (go-name->url name))
+              (commit (commit name))
+              (inputs (dependencies->inputs (dependencies name)))
+              (synopsis (synopsis name))
+              (description (description name)))
+          (call-with-temporary-directory
+           (lambda (temp)
+             (and (git-fetch source-url commit temp)
+                  `(package
+                     (name ,(go-name->guix-name name))
+                     (version ,version)
+                     (source
+                      (origin
+                        (method git-fetch)
+                        (uri (git-reference
+                              (url ,source-url)
+                              (commit ,commit)))
+                        (file-name (git-file-name name version))
+                        (sha256 (base32 ,(guix-hash-directory temp)))))
+                     (build-system go-build-system)
+                     ,@(if (null? inputs)
+                           '()
+                           `((inputs ,(list 'quasiquote inputs))))
+                     (home-page ,source-url)
+                     (synopsis ,synopsis)
+                     (description ,description)
+                     (license ,@(string->license name))))))))))
+#;
+(go->guix-package "github.com/gogo/protobuf")
+
+;; Debug
+#;
+(display
+ (call-with-temporary-directory
+  (lambda (temp)
+    (let* ((name "github.com/gogo/protobuf")
+           (url (go-name->url name))
+           (commit "28a6bbf47e48e0b2220b2a244750b660c83d4942"))
+      (let ((path (string-append "/tmp" name)))
+        (git-fetch url commit temp)
+        (guix-hash . ("-r" "-x" temp)))))))
diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index 2a3b7341f..23948e402 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -34,6 +34,7 @@
   #:use-module (guix gexp)
   #:use-module (guix store)
   #:use-module (guix download)
+  #:use-module (guix scripts hash)
   #:use-module (gnu packages)
   #:use-module (ice-9 match)
   #:use-module (ice-9 rdelim)
@@ -50,6 +51,7 @@
 
             url-fetch
             guix-hash-url
+            guix-hash-directory
 
             package-names->package-inputs
             maybe-inputs
@@ -125,6 +127,9 @@ recursively apply the procedure to the sub-list."
   "Return the hash of FILENAME in nix-base32 format."
   (bytevector->nix-base32-string (file-sha256 filename)))
 
+(define (guix-hash-directory dir)
+  (guix-hash . ("-r" "-x" dir)))
+
 (define (spdx-string->license str)
   "Convert STR, a SPDX formatted license identifier, to a license object.
    Return #f if STR does not match any known identifiers."
-- 
2.19.2


  reply	other threads:[~2019-08-06 20:26 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-06 10:23 Go importer - help with git-fetch swedebugia
2019-08-06 10:26 ` Pierre Neidhardt
2019-08-06 12:45   ` swedebugia
2019-08-06 12:56 ` Ricardo Wurmus
2019-08-06 13:04   ` Jakob L. Kreuze
2019-08-06 20:26     ` swedebugia [this message]
2019-08-06 20:46       ` Jakob L. Kreuze
2019-08-06 22:02       ` Ricardo Wurmus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7ff3ff2d-0e35-8b57-8b0c-28e0ccfda326@riseup.net \
    --to=swedebugia@riseup.net \
    --cc=guix-devel@gnu.org \
    --cc=zerodaysfordays@sdf.lonestar.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.