From 833f1d81e9deb048f4c22f017b8114cbb9793e16 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 11:39:01 -0400 Subject: [PATCH 1/8] Took snippet from platform/platform-packaging/ --- Haskell/DockerfileExample.hs | 108 +++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Haskell/DockerfileExample.hs diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs new file mode 100644 index 0000000..f4c8d60 --- /dev/null +++ b/Haskell/DockerfileExample.hs @@ -0,0 +1,108 @@ +#!/usr/bin/env nix-shell +#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz --pure -i runhaskell -p "pkgs.haskell.packages.ghc881.ghcWithPackages (ps: with ps; [ dockerfile containers ])" +{-# OPTIONS_GHC -Wall -Werror #-} +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DeriveDataTypeable #-} + +import "base" Data.Foldable (foldl') +import "base" GHC.Generics (Generic) +import "base" Data.Typeable (Typeable) +import "base" Data.Data (Data) +import "containers" Data.Map.Strict (Map, empty) +import "dockerfile" Data.Docker + +data OS = Ubuntu + | RedHat + | CentOS + deriving (Show, Read, Eq, Ord, Enum, Bounded, Data, Typeable, Generic) + +data User = Root + | User { _user_name :: !String } + +type Entrypoint = (String, [String]) + +data ContainerEnv = ContainerEnv + { _containerEnv_OS :: !OS + , _containerEnv_users :: ![User] + , _containerEnv_image :: !String + , _containerEnv_installations :: ![(String, [String])] + , _containerEnv_env :: !(Map String String) + , _containerEnv_runCmds :: ![String] + , _containerEnv_entrypoint :: !(Maybe Entrypoint) + , _containerEnv_command :: !(Maybe [String]) + } deriving (Show, Read, Eq, Ord, Data, Typeable, Generic) + +aptInstalls :: (String, [String]) +aptInstalls = ("apt-get install -yq", ["python3", "python3-pip", "wget", "tar"]) + +pipInstalls :: (String, [String]) +pipInstalls = ("pip3 install --user", ["jupyter"]) + +runCmds :: [String] +runCmds = ["wget http://apache.mirrors.hoobly.com/drill/drill-1.16.0/apache-drill-1.16.0.tar.gz", "tar -xzvf apache-drill-1.16.0.tar.gz"] + +jupyter :: Entrypoint +jupyter = ["jupyter", "notebook", "--ip-0.0.0.0", "--no-browser"] + +example :: ContainerEnv +example = ContainerEnv Ubuntu + ["atidot"] + "ubuntu" + [aptInstalls, pipInstalls] + empty + runCmds + (Just jupyter) + Nothing + +toDocker :: ContainerEnv -> Docker () +toDocker (ContainerEnv os users img pkgs environment runCmds entrypoint' command) = do + from img + foreach (makeUser os) users + foreach (uncurry installPkgs) pkgs + foreach (uncurry env) $ assocs environment + foreach run runCmds + doIfJust (curry entrypoint) entrypoint' + doIfJust cmd command + where doIfJust f Nothing = return () + doIfJust f (Just x) = f x + +foreach :: (a -> Docker ()) + -> [a] + -> Docker () +foreach f xs = foldl' (>>) (return ()) (map f xs) + +installPkgs :: String + -> [String] + -> Docker () +installPkgs installer pkgs = run installation + where installation = foldl' (++) (installer ++ endl1) (map instLine pkgs) + instLine pkg = " " ++ pkg ++ endl pkg + endl pkg = replicate (maxLength - paddedLength pkg) ' ' ++ " \\\n" + paddedLine1 = "RUN " ++ installer ++ " \\" + endl1 = replicate (maxLength - length paddedLine1) ' ' ++ " \\\n" + maxLength = maximum $ map length (paddedLine1 : map pad pkgs) + paddedLength = length . pad + pad pkg = " " ++ pkg ++ " \\" + +addUserProgram :: OS -> String +addUserProgram Ubuntu = "adduser" +addUserProgram CentOS = "adduser" +addUserProgram RedHat = "useradd" + +makeUser :: OS + -> User + -> Docker () +makeUser _ Root = return () +makeUser os (User uname) = do + run (addUserProgram os ++ " " ++ uname) + user uname + workdir ("/home/" ++ uname) + env "PATH" "/home/atidot/.local/bin:${PATH}" + +main :: IO () +main = do + pwd <- getCurrentDirectory + let dockerPath = pwd ++ "/DockerfileExample" + dockerfileWrite dockerPath $ toDocker example From ba91b40c82f05092172be7e400b45f7c13707fda Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 12:09:55 -0400 Subject: [PATCH 2/8] Fixed type bugs --- Haskell/DockerfileExample.hs | 3 +++ 1 file changed, 3 insertions(+) mode change 100644 => 100755 Haskell/DockerfileExample.hs diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs old mode 100644 new mode 100755 index f4c8d60..1d7a33f --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -5,6 +5,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveGeneric #-} import "base" Data.Foldable (foldl') import "base" GHC.Generics (Generic) @@ -12,6 +13,7 @@ import "base" Data.Typeable (Typeable) import "base" Data.Data (Data) import "containers" Data.Map.Strict (Map, empty) import "dockerfile" Data.Docker +import "directory" System.Directory (getCurrentDirectory) data OS = Ubuntu | RedHat @@ -20,6 +22,7 @@ data OS = Ubuntu data User = Root | User { _user_name :: !String } + deriving (Show, Read, Eq, Ord, Enum, Data, Typeable, Generic) type Entrypoint = (String, [String]) From dd7bed9b7c254ce6133c440dd12bdbd22d7bd017 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 12:29:37 -0400 Subject: [PATCH 3/8] Another type bugfix --- Haskell/DockerfileExample.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 1d7a33f..4f324e9 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -22,7 +22,7 @@ data OS = Ubuntu data User = Root | User { _user_name :: !String } - deriving (Show, Read, Eq, Ord, Enum, Data, Typeable, Generic) + deriving (Show, Read, Eq, Ord, Data, Typeable, Generic) type Entrypoint = (String, [String]) From f7cd02e3f9ef7e4b124460b05fc698c7fe449478 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 12:39:15 -0400 Subject: [PATCH 4/8] Fixed missing import --- Haskell/DockerfileExample.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 4f324e9..274146d 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -11,7 +11,7 @@ import "base" Data.Foldable (foldl') import "base" GHC.Generics (Generic) import "base" Data.Typeable (Typeable) import "base" Data.Data (Data) -import "containers" Data.Map.Strict (Map, empty) +import "containers" Data.Map.Strict (Map, empty, assocs) import "dockerfile" Data.Docker import "directory" System.Directory (getCurrentDirectory) From 55a1a7865d9de6c83d73ff03eb06a5807c31c6c0 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 13:44:17 -0400 Subject: [PATCH 5/8] Fixed currying bug --- Haskell/DockerfileExample.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 274146d..646f2ac 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -47,7 +47,7 @@ runCmds :: [String] runCmds = ["wget http://apache.mirrors.hoobly.com/drill/drill-1.16.0/apache-drill-1.16.0.tar.gz", "tar -xzvf apache-drill-1.16.0.tar.gz"] jupyter :: Entrypoint -jupyter = ["jupyter", "notebook", "--ip-0.0.0.0", "--no-browser"] +jupyter = ("jupyter", ["notebook", "--ip-0.0.0.0", "--no-browser"]) example :: ContainerEnv example = ContainerEnv Ubuntu @@ -66,7 +66,7 @@ toDocker (ContainerEnv os users img pkgs environment runCmds entrypoint' command foreach (uncurry installPkgs) pkgs foreach (uncurry env) $ assocs environment foreach run runCmds - doIfJust (curry entrypoint) entrypoint' + doIfJust (uncurry entrypoint) entrypoint' doIfJust cmd command where doIfJust f Nothing = return () doIfJust f (Just x) = f x From 880628b3caa8d920a39d590de105c9a80fe33780 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 13:50:39 -0400 Subject: [PATCH 6/8] Fixed variable missing constructor --- Haskell/DockerfileExample.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 646f2ac..1a120c8 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -51,7 +51,7 @@ jupyter = ("jupyter", ["notebook", "--ip-0.0.0.0", "--no-browser"]) example :: ContainerEnv example = ContainerEnv Ubuntu - ["atidot"] + [User "atidot"] "ubuntu" [aptInstalls, pipInstalls] empty From ed75fdd851385d673cda16b7d232c54e0a0e4854 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 14:58:36 -0400 Subject: [PATCH 7/8] Fixed name shadowing and unused name --- Haskell/DockerfileExample.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 1a120c8..7a31d97 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -60,15 +60,15 @@ example = ContainerEnv Ubuntu Nothing toDocker :: ContainerEnv -> Docker () -toDocker (ContainerEnv os users img pkgs environment runCmds entrypoint' command) = do +toDocker (ContainerEnv os users img pkgs environment toRun entrypoint' command) = do from img foreach (makeUser os) users foreach (uncurry installPkgs) pkgs foreach (uncurry env) $ assocs environment - foreach run runCmds + foreach run toRun doIfJust (uncurry entrypoint) entrypoint' doIfJust cmd command - where doIfJust f Nothing = return () + where doIfJust _ Nothing = return () doIfJust f (Just x) = f x foreach :: (a -> Docker ()) From 90a49d75c8edc3310a8af7a1e5a2fa148c0967c8 Mon Sep 17 00:00:00 2001 From: Curran McConnell Date: Tue, 19 Nov 2019 15:06:28 -0400 Subject: [PATCH 8/8] Standardized whitespacing --- Haskell/DockerfileExample.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Haskell/DockerfileExample.hs b/Haskell/DockerfileExample.hs index 7a31d97..9a577f5 100755 --- a/Haskell/DockerfileExample.hs +++ b/Haskell/DockerfileExample.hs @@ -76,10 +76,12 @@ foreach :: (a -> Docker ()) -> Docker () foreach f xs = foldl' (>>) (return ()) (map f xs) +-- The last character of the string passed to `run` would be '\n' without the +-- call to `take`. Removing the '\n' standardizes the whitespace. installPkgs :: String -> [String] -> Docker () -installPkgs installer pkgs = run installation +installPkgs installer pkgs = run (take (length installation - 1) installation) where installation = foldl' (++) (installer ++ endl1) (map instLine pkgs) instLine pkg = " " ++ pkg ++ endl pkg endl pkg = replicate (maxLength - paddedLength pkg) ' ' ++ " \\\n"