jkawamoto/roadie-queue-manager

View on GitHub
exec.go

Summary

Maintainability
A
1 hr
Test Coverage
//
// exec.go
//
// Copyright (c) 2016-2017 Junpei Kawamoto
//
// This file is part of Roadie queue manager.
//
// Roadie Queue Manager 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.
//
// Roadie Queue Manager 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 Roadie queue manager. If not, see <http://www.gnu.org/licenses/>.
//

package main

import (
    "context"
    "fmt"
    "log"
    "path/filepath"
    "regexp"
    "strings"

    "github.com/jkawamoto/roadie-azure/roadie"
    "github.com/jkawamoto/roadie/script"
)

var (
    // RegexpDropboxURL defines a regular expression of a dropbox URL.
    RegexpDropboxURL = regexp.MustCompile(`dropbox://(?:www.dropbox.com/)?(sh?)/([^?]+)(?:\?[^:]+)?(:.*)?`)
    // DefaultDropboxArchive defines a default file name for archive files downloaded from dropbox.
    DefaultDropboxArchive = "dropbox.zip"
)

// ExecuteScript creates a sandbox container and runs a given script in the container.
func ExecuteScript(ctx context.Context, s *script.Script, logger *log.Logger) (err error) {

    logger.Println("Creating a Dockerfile and an entrypoint.sh")
    dockerfile, err := Dockerfile(s)
    if err != nil {
        return
    }
    entrypoint, err := Entrypoint(newEntrypointOpt(s))
    if err != nil {
        return
    }

    cli, err := roadie.NewDockerClient(logger)
    if err != nil {
        return
    }
    defer cli.Close()

    err = cli.Build(ctx, &roadie.DockerBuildOpt{
        ImageName:  s.Name,
        Dockerfile: dockerfile,
        Entrypoint: entrypoint,
    })
    if err != nil {
        return
    }

    err = cli.Start(ctx, s.Name, nil)
    if err != nil {
        return
    }

    return
}

// newEntrypointOpt creates a new set of options from a given script.
func newEntrypointOpt(s *script.Script) (opt *EntrypointOpt) {
    opt = new(EntrypointOpt)

    // Parse source section
    switch {
    case strings.HasSuffix(s.Source, ".git"):
        opt.Git = s.Source
    case strings.HasPrefix(s.Source, "gs://"):
        opt.GSFiles = append(opt.GSFiles, parseURL(s.Source))
    default:
        opt.Downloads = append(opt.Downloads, parseURL(s.Source))
    }

    // Parse data section
    for _, u := range s.Data {
        if strings.HasPrefix(u, "gs://") {
            opt.GSFiles = append(opt.GSFiles, parseURL(u))
        } else {
            opt.Downloads = append(opt.Downloads, parseURL(u))
        }
    }

    // Set running commands.
    opt.Run = s.Run

    // Parse result and upload section
    opt.Result = s.Result
    if !strings.HasSuffix(opt.Result, "/") {
        opt.Result += "/"
    }
    opt.Uploads = s.Upload

    return
}

// parseURL parses an extended URL and returns a download option.
func parseURL(u string) (opt DownloadOpt) {

    var noExpand bool
    if strings.HasPrefix(u, "dropbox://") {
        // The given URL has schema dropbox://
        m := RegexpDropboxURL.FindStringSubmatch(u)

        basename := DefaultDropboxArchive
        if m[1] == "s" {
            basename = filepath.Base(m[2])
        }

        opt.Src = fmt.Sprintf("https://www.dropbox.com/%v/%v?dl=1", m[1], m[2])
        if m[3] != "" {
            // The given URL has a renaming option.
            if strings.HasSuffix(m[3], "/") {
                opt.Dest = filepath.Join(strings.TrimPrefix(m[3], ":"), basename)

            } else {
                opt.Dest = strings.TrimPrefix(m[3], ":")
                noExpand = true
            }

        } else {
            // The given URL doesn't have a renaming option.
            opt.Dest = basename
        }

    } else {
        // The given URL has other schemae.
        lhs := strings.Index(u, ":")
        rhs := strings.LastIndex(u, ":")
        if lhs == rhs {
            // The given URL doesn't have a renaming option.
            opt.Src = u
            opt.Dest = filepath.Base(opt.Src)

        } else {
            // The given URL has a renaming option.
            opt.Src = u[:rhs]
            target := u[rhs+1:]
            if strings.HasSuffix(target, "/") {
                opt.Dest = filepath.Join(target, filepath.Base(opt.Src))
            } else {
                noExpand = true
                opt.Dest = target
            }

        }

    }

    if !noExpand {
        switch {
        case strings.HasSuffix(opt.Dest, ".zip"):
            opt.Zip = true
        case strings.HasSuffix(opt.Dest, ".tar.gz"):
            opt.TarGz = true
        case strings.HasSuffix(opt.Dest, ".tar"):
            opt.Tar = true
        }
    }

    return

}