Skip to content
This repository has been archived by the owner on Mar 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1 from everettraven/feature/install_subcommand_v1
Browse files Browse the repository at this point in the history
install subcommand
  • Loading branch information
everettraven authored May 20, 2021
2 parents c5c6afe + 6097880 commit c33b785
Show file tree
Hide file tree
Showing 8 changed files with 1,387 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
17 changes: 17 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module github.com/everettraven/packageless

go 1.16

require (
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/containerd/containerd v1.5.1 // indirect
github.com/docker/docker v20.10.6+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/hashicorp/hcl2 v0.0.0-20191002203319-fb75b3253c80 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
google.golang.org/grpc v1.37.1 // indirect
)
947 changes: 947 additions & 0 deletions go.sum

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"fmt"
"os"

"github.com/everettraven/packageless/utils"
)

func main() {
if err := utils.SubCommand(os.Args[1:]); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
16 changes: 16 additions & 0 deletions package_list.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package "python" {
image="packageless/python"
volume {
path="./python/packages/"
mount="/usr/local/lib/python3.9/site-packages/"
}

volume {
mount="/run/"
}

copy {
source="/usr/local/lib/python3.9/site-packages/"
dest="./python/packages/"
}
}
177 changes: 177 additions & 0 deletions utils/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package utils

import (
"archive/tar"
"context"
"io"
"os"
"path/filepath"
"strings"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)

//PullImage - This function pulls a Docker Image from the packageless organization in Docker Hub
func PullImage(name string) error {
//Set up a Docker API client
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

//Check for errors
if err != nil {
return err
}

//Set the context
ctx := context.Background()

//Begin pulling the image
out, err := cli.ImagePull(ctx, name, types.ImagePullOptions{})

//Check for errors
if err != nil {
return err
}

//Close the output buffer after the function exits
defer out.Close()

//Copy the output to the screen
io.Copy(os.Stdout, out)

//No errors
return nil
}

//CreateContainer - Create a Docker Container from a Docker Image. Returns the containerID and any errors
func CreateContainer(image string) (string, error) {
//Create the client
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

//Check for errors
if err != nil {
return "", err
}

//Create the context and create the container
ctx := context.Background()
container, err := cli.ContainerCreate(ctx, &container.Config{Image: image, Cmd: []string{"bash"}}, nil, nil, nil, "")

//Check for errors
if err != nil {
return "", err
}

//No errors
return container.ID, err
}

//CopyFromContainer will copy files from within a Docker Container to the source location on the host
func CopyFromContainer(source string, dest string, containerID string) error {
//Create the Docker client
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

//Check for errors
if err != nil {
return err
}

//Set the context and begin copying from the container
ctx := context.Background()
reader, _, err := cli.CopyFromContainer(ctx, containerID, source)

//Check for errors
if err != nil {
return err
}

//Close the reader after the function ends
defer reader.Close()

//Create a tar Reader
tarReader := tar.NewReader(reader)

//Skip the first header as it is the source folder name
tarReader.Next()

//Loop through the reader and write the files
for {
//Get the tar header
header, err := tarReader.Next()
//Make sure we havent reached the end of the tar
if err == io.EOF {
break
} else if err != nil {
return err
}

newHeaderPath := strings.Split(header.Name, "/")[1:]
joinPath := strings.Join(newHeaderPath[:], "/")

//Create the destination file path on the host
path := filepath.Join(dest, joinPath)
//Get the file info from the header
info := header.FileInfo()

//Check if the current file is a directory
if info.IsDir() {

//Check if the directory exists
if _, err = os.Stat(path); err != nil {
if os.IsNotExist(err) {
//Make the directory
err = os.MkdirAll(path, info.Mode())
} else {
return err
}
}

} else {
//Create the file and open it in the destination path on the host
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())

//Check for errors
if err != nil {
return err
}

//Copy the contents of the tar reader to the file
_, err = io.Copy(file, tarReader)

//Check for errors
if err != nil {
return err
}

//Close the file when all the writing is finished
file.Close()
}

}

return nil
}

//RemoveContainer is used to remove a container Docker given the container ID
func RemoveContainer(containerID string) error {
//Create the Docker API client
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

//Check for errors
if err != nil {
return err
}

//Create the context and remove the container
ctx := context.Background()
err = cli.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{Force: true})

//Check for errors
if err != nil {
return err
}

//No Errors
return nil
}
60 changes: 60 additions & 0 deletions utils/hcl_parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package utils

import (
"errors"

"github.com/hashicorp/hcl2/gohcl"
"github.com/hashicorp/hcl2/hclparse"
)

//Copy object to parse the copy block in the package list
type Copy struct {
Source string `hcl:"source,attr"`
Dest string `hcl:"dest,attr"`
}

//Volume object to parse the volume block in the package list
type Volume struct {
Path string `hcl:"path,optional"`
Mount string `hcl:"mount,attr"`
}

//Package object to parse the package block in the package list
type Package struct {
Name string `hcl:"name,label"`
Image string `hcl:"image,attr"`
Volumes []Volume `hcl:"volume,block"`
Copies []Copy `hcl:"copy,block"`
}

//PackageHCLUtil object to contain a list of packages and all their attributes after the parsing of the package list
type PackageHCLUtil struct {
Packages []Package `hcl:"package,block"`
}

//Parse function to parse the HCL file given in the filepath
func Parse(filepath string) (PackageHCLUtil, error) {
//Create a parser
parser := hclparse.NewParser()

//Create the object to be decoded to
var packages PackageHCLUtil

//Parse the data
parseData, parseDiags := parser.ParseHCLFile(filepath)

//Check for errors
if parseDiags.HasErrors() {
return packages, errors.New("ParseDiags: " + parseDiags.Error())
}

//Decode the parsed HCL to the Object
decodeDiags := gohcl.DecodeBody(parseData.Body, nil, &packages)

//Check for errors
if decodeDiags.HasErrors() {
return packages, errors.New("DecodeDiags: " + decodeDiags.Error())
}

return packages, nil
}
Loading

0 comments on commit c33b785

Please sign in to comment.