Search code examples
schemeracketrequire

How do I execute the call to require after the execution on system has ended?


The following code is supposed to install colorize, use it, and then uninstall the package:


#!/usr/bin/env racket
#lang racket

(system "raco pkg install colorize")

(require colorize)
(display (colorize "Italic" 'default #:style 'italic))
(newline)

(system "raco pkg remove colorize")

It does not work - even though require is below the call to system Racket somehow attempt to execute (require colorize) before executing (system "raco pkg install colorize").

In Python I solved similar problem with try except, e.g.:


from subprocess import run
from sys import modules

try:
    from bs4 import BeautifulSoup
except:
    run("pip3 install beautifulsoup4", shell=True)
    from bs4 import BeautifulSoup

#The rest of the code that does scraping.

In Bash I would use if or &&. How might I solve this in Racket so that the installation of dependencies gets automated away.

P.S. I am aware that the goal that I'm trying to achieve may not be good practice from the security standpoint, but let this be outside of the scope of the question.


Solution

  • I think doing something like this really ought not to be possible. Consider how you would compile such a program, for instance: the module you need will simply not be available at compile time.

    The right answer to this problem is to write wrappers for things like this which ensure that the right packages are installed.

    However this horrible abuse sort-of half works. But don't use this: write a wrapper: it's not that hard.

    #!/usr/bin/env racket
    #lang racket
    
    ;;; DO NOT USE THIS. May explode on contact.  Harmful to fish.
    ;;; 
    (begin-for-syntax
      (require pkg pkg/lib)
      (when (not (member "colorize" (installed-pkg-names)))
        (pkg-install-command "colorize" #:auto #t)))
    
    (require colorize)
    ...