From: Andrew Tropin <andrew@trop.in>
To: 50296@debbugs.gnu.org
Subject: [bug#50296] [PATCH 2/2] scripts: home: Add import subcommand.
Date: Tue, 31 Aug 2021 12:40:58 +0300 [thread overview]
Message-ID: <87v93mhryt.fsf@trop.in> (raw)
In-Reply-To: <handler.50296.B.16304022327647.ack@debbugs.gnu.org>
[-- Attachment #1: Type: text/plain, Size: 12300 bytes --]
* guix/scripts/home/import.scm: New file.
* Makefile.am (MODULES): Add it.
---
Makefile.am | 1 +
guix/scripts/home.scm | 2 +-
guix/scripts/home/import.scm | 241 +++++++++++++++++++++++++++++++++++
3 files changed, 243 insertions(+), 1 deletion(-)
create mode 100644 guix/scripts/home/import.scm
diff --git a/Makefile.am b/Makefile.am
index d44360c034..c27dcf9a38 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -296,6 +296,7 @@ MODULES = \
guix/scripts/system/search.scm \
guix/scripts/system/reconfigure.scm \
guix/scripts/home.scm \
+ guix/scripts/home/import.scm \
guix/scripts/lint.scm \
guix/scripts/challenge.scm \
guix/scripts/import/crate.scm \
diff --git a/guix/scripts/home.scm b/guix/scripts/home.scm
index 9eb5c0c917..75df6d707d 100644
--- a/guix/scripts/home.scm
+++ b/guix/scripts/home.scm
@@ -36,7 +36,7 @@
#:use-module (guix scripts build)
#:use-module (guix scripts system search)
#:autoload (guix scripts pull) (channel-commit-hyperlink)
- ;; #:use-module (guix scripts home import)
+ #:use-module (guix scripts home import)
#:use-module ((guix status) #:select (with-status-verbosity))
#:use-module (guix gexp)
#:use-module (guix monads)
diff --git a/guix/scripts/home/import.scm b/guix/scripts/home/import.scm
new file mode 100644
index 0000000000..39f45dbeac
--- /dev/null
+++ b/guix/scripts/home/import.scm
@@ -0,0 +1,241 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;;
+;;; 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 scripts home import)
+ #:use-module (guix profiles)
+ #:use-module (guix ui)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 pretty-print)
+ #:use-module (srfi srfi-1)
+ #:export (import-manifest))
+
+;;; Commentary:
+;;;
+;;; This module provides utilities for generating home service
+;;; configurations from existing "dotfiles".
+;;;
+;;; Code:
+
+
+(define (generate-bash-module+configuration)
+ (let ((rc (string-append (getenv "HOME") "/.bashrc"))
+ (profile (string-append (getenv "HOME") "/.bash_profile"))
+ (logout (string-append (getenv "HOME") "/.bash_logout")))
+ `((gnu home-services bash)
+ (service home-bash-service-type
+ (home-bash-configuration
+ ,@(if (file-exists? rc)
+ `((bashrc
+ (list (slurp-file-gexp (local-file ,rc)))))
+ '())
+ ,@(if (file-exists? profile)
+ `((bash-profile
+ (list (slurp-file-gexp
+ (local-file ,profile)))))
+ '())
+ ,@(if (file-exists? logout)
+ `((bash-logout
+ (list (slurp-file-gexp
+ (local-file ,logout)))))
+ '()))))))
+
+
+(define %files-configurations-alist
+ `((".bashrc" . ,generate-bash-module+configuration)
+ (".bash_profile" . ,generate-bash-module+configuration)
+ (".bash_logout" . ,generate-bash-module+configuration)))
+
+(define (modules+configurations)
+ (let ((configurations (delete-duplicates
+ (filter-map (match-lambda
+ ((file . proc)
+ (if (file-exists?
+ (string-append (getenv "HOME") "/" file))
+ proc
+ #f)))
+ %files-configurations-alist)
+ (lambda (x y)
+ (equal? (procedure-name x) (procedure-name y))))))
+ (map (lambda (proc) (proc)) configurations)))
+
+;; Based on `manifest->code' from (guix profiles)
+;; MAYBE: Upstream it?
+(define* (manifest->code manifest
+ #:key
+ (entry-package-version (const ""))
+ (home-environment? #f))
+ "Return an sexp representing code to build an approximate version of
+MANIFEST; the code is wrapped in a top-level 'begin' form. If
+HOME-ENVIRONMENT? is #t, return an <home-environment> definition.
+Call ENTRY-PACKAGE-VERSION to determine the version number to use in
+the spec for a given entry; it can be set to 'manifest-entry-version'
+for fully-specified version numbers, or to some other procedure to
+disambiguate versions for packages for which several versions are
+available."
+ (define (entry-transformations entry)
+ ;; Return the transformations that apply to ENTRY.
+ (assoc-ref (manifest-entry-properties entry) 'transformations))
+
+ (define transformation-procedures
+ ;; List of transformation options/procedure name pairs.
+ (let loop ((entries (manifest-entries manifest))
+ (counter 1)
+ (result '()))
+ (match entries
+ (() result)
+ ((entry . tail)
+ (match (entry-transformations entry)
+ (#f
+ (loop tail counter result))
+ (options
+ (if (assoc-ref result options)
+ (loop tail counter result)
+ (loop tail (+ 1 counter)
+ (alist-cons options
+ (string->symbol
+ (format #f "transform~a" counter))
+ result)))))))))
+
+ (define (qualified-name entry)
+ ;; Return the name of ENTRY possibly with "@" followed by a version.
+ (match (entry-package-version entry)
+ ("" (manifest-entry-name entry))
+ (version (string-append (manifest-entry-name entry)
+ "@" version))))
+
+ (if (null? transformation-procedures)
+ (let ((specs (map (lambda (entry)
+ (match (manifest-entry-output entry)
+ ("out" (qualified-name entry))
+ (output (string-append (qualified-name entry)
+ ":" output))))
+ (manifest-entries manifest))))
+ (if home-environment?
+ (let ((modules+configurations (modules+configurations)))
+ `(begin
+ (use-modules (gnu home)
+ (gnu packages)
+ ,@(map first modules+configurations))
+ ,(home-environment-template
+ #:specs specs
+ #:services (map second modules+configurations))))
+ `(begin
+ (use-modules (gnu packages))
+
+ (specifications->manifest
+ (list ,@specs)))))
+ (let* ((transform (lambda (options exp)
+ (if (not options)
+ exp
+ (let ((proc (assoc-ref transformation-procedures
+ options)))
+ `(,proc ,exp)))))
+ (packages (map (lambda (entry)
+ (define options
+ (entry-transformations entry))
+
+ (define name
+ (qualified-name entry))
+
+ (match (manifest-entry-output entry)
+ ("out"
+ (transform options
+ `(specification->package ,name)))
+ (output
+ `(list ,(transform
+ options
+ `(specification->package ,name))
+ ,output))))
+ (manifest-entries manifest)))
+ (transformations (map (match-lambda
+ ((options . name)
+ `(define ,name
+ (options->transformation ',options))))
+ transformation-procedures)))
+ (if home-environment?
+ (let ((modules+configurations (modules+configurations)))
+ `(begin
+ (use-modules (guix transformations)
+ (gnu home)
+ (gnu packages)
+ ,@(map first modules+configurations))
+
+ ,@transformations
+
+ ,(home-environment-template
+ #:packages packages
+ #:services (map second modules+configurations))))
+ `(begin
+ (use-modules (guix transformations)
+ (gnu packages))
+
+ ,@transformations
+
+ (packages->manifest
+ (list ,@packages)))))))
+
+(define* (home-environment-template #:key (packages #f) (specs #f) services)
+ "Return an S-exp containing a <home-environment> declaration
+containing PACKAGES, or SPECS (package specifications), and SERVICES."
+ `(home-environment
+ (packages
+ ,@(if packages
+ `((list ,@packages))
+ `((map specification->package
+ (list ,@specs)))))
+ (services (list ,@services))))
+
+(define* (import-manifest
+ manifest
+ #:optional (port (current-output-port)))
+ "Write to PORT a <home-environment> corresponding to MANIFEST."
+ (define (version-spec entry)
+ (let ((name (manifest-entry-name entry)))
+ (match (map package-version (find-packages-by-name name))
+ ((_)
+ ;; A single version of NAME is available, so do not specify the
+ ;; version number, even if the available version doesn't match ENTRY.
+ "")
+ (versions
+ ;; If ENTRY uses the latest version, don't specify any version.
+ ;; Otherwise return the shortest unique version prefix. Note that
+ ;; this is based on the currently available packages, which could
+ ;; differ from the packages available in the revision that was used
+ ;; to build MANIFEST.
+ (let ((current (manifest-entry-version entry)))
+ (if (every (cut version>? current <>)
+ (delete current versions))
+ ""
+ (version-unique-prefix (manifest-entry-version entry)
+ versions)))))))
+
+ (match (manifest->code manifest
+ #:entry-package-version version-spec
+ #:home-environment? #t)
+ (('begin exp ...)
+ (format port (G_ "\
+;; This \"home-environment\" file can be passed to 'guix home reconfigure'
+;; to reproduce the content of your profile. This is \"symbolic\": it only
+;; specifies package names. To reproduce the exact same profile, you also
+;; need to capture the channels being used, as returned by \"guix describe\".
+;; See the \"Replicating Guix\" section in the manual.\n"))
+ (for-each (lambda (exp)
+ (newline port)
+ (pretty-print exp port))
+ exp))))
--
2.33.0
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
next prev parent reply other threads:[~2021-08-31 9:42 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-31 9:28 [bug#50296] [PATCH 0/2] Add 'guix home' command Andrew Tropin
[not found] ` <handler.50296.B.16304022327647.ack@debbugs.gnu.org>
2021-08-31 9:40 ` [bug#50296] [PATCH 1/2] scripts: Add 'guix home' Andrew Tropin
2021-08-31 10:53 ` zimoun
2021-08-31 12:12 ` Andrew Tropin
2021-08-31 13:09 ` zimoun
2021-09-01 5:20 ` Andrew Tropin
2021-08-31 9:40 ` Andrew Tropin [this message]
2021-08-31 10:46 ` [bug#50296] [PATCH 0/2] Add 'guix home' command zimoun
2021-08-31 12:03 ` Andrew Tropin
2021-08-31 11:13 ` bug#50296: " Oleg Pykhalov
2021-08-31 11:46 ` [bug#50296] " Andrew Tropin
2021-08-31 12:47 ` Andrew Tropin
2021-08-31 14:23 ` Oleg Pykhalov
2021-09-01 5:36 ` Andrew Tropin
2021-09-09 6:10 ` Andrew Tropin
2021-09-09 17:45 ` Oleg Pykhalov
2021-09-10 5:31 ` Andrew Tropin
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
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87v93mhryt.fsf@trop.in \
--to=andrew@trop.in \
--cc=50296@debbugs.gnu.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 public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).