예제 #1
0
파일: main.go 프로젝트: kr/hpush
func main() {
	signal.Notify(make(chan os.Signal), syscall.SIGHUP) // ignore

	devNull, err := os.Open(os.DevNull)
	if err != nil {
		panic(err)
	}
	syscall.Dup2(int(devNull.Fd()), 0)
	syscall.Dup2(int(devNull.Fd()), 1)
	syscall.Dup2(int(devNull.Fd()), 2)

	err = os.Remove(selfPath)
	if err != nil {
		panic(err)
	}
	u, err := url.Parse(os.Args[1])
	if err != nil {
		panic(err)
	}
	addr, err := net.ResolveTCPAddr("tcp", u.Host)
	if err != nil {
		panic(err)
	}
	c, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		panic(err)
	}
	io.WriteString(c, "X "+u.Path+" HTTP/1.1\r\n\r\n")

	t, slugURL, err := msg.ReadFull(c)
	if err != nil {
		fail(c, err)
	}
	if t != msg.File {
		fail(c, fmt.Sprintf("wanted file, got %d\n", t))
	}

	r, err := msg.ReadFile(c)
	if err != nil {
		fail(c, err)
	}
	f, err := spool(r)
	if err != nil {
		fail(c, err)
	}
	msg.Write(c, msg.User, []byte(fmt.Sprintf("read tarball\n")))
	err = os.MkdirAll(buildDir, 0777)
	if err != nil {
		fail(c, err)
	}
	err = tarutil.ExtractAll(f, buildDir, 0)
	if err != nil {
		fail(c, err)
	}
	msg.Write(c, msg.User, []byte("extracted\n"))
	err = os.MkdirAll(cacheDir, 0777)
	if err != nil {
		fail(c, err)
	}

	bpurl := os.Getenv("BUILDPACK_URL")
	if bpurl == "" {
		errorExit(c, "no BUILDPACK_URL\n")
	}
	u, urlerr := url.Parse(bpurl)
	if urlerr == nil && u.Fragment != "" {
		bpurl = bpurl[:len(bpurl)-len(u.Fragment)-1]
	}
	msg.Write(c, msg.User, []byte("fetching buildpack\n"))
	msg.Write(c, msg.User, []byte(bpurl+"\n"))
	cmd := exec.Command("git", "clone", bpurl, bpDir)
	err = cmd.Run()
	if err != nil {
		msg.Write(c, msg.User, []byte(err.Error()+"\n"))
		errorExit(c, "failed to fetch buildpack\n")
	}
	if urlerr == nil && u.Fragment != "" {
		msg.Write(c, msg.User, []byte("git checkout "+u.Fragment+"\n"))
		cmd := exec.Command("git", "checkout", u.Fragment)
		cmd.Dir = bpDir
		err = cmd.Run()
		if err != nil {
			msg.Write(c, msg.User, []byte(err.Error()+"\n"))
			errorExit(c, "failed to check out ref: "+u.Fragment+"\n")
		}
	}
	err = os.RemoveAll(buildDir + "/.git")
	if err != nil {
		msg.Write(c, msg.User, []byte(err.Error()+"\n"))
		errorExit(c, "failed to clean .git dir\n")
	}

	msg.Write(c, msg.User, []byte("compiling\n"))
	cmd = exec.Command(compile, buildDir, cacheDir)
	cmd.Stdout = msg.LineWriter(c, msg.User)
	cmd.Stderr = cmd.Stdout
	err = cmd.Run()
	if ee, ok := err.(*exec.ExitError); ok {
		errorExit(c, "buildpack failed: "+ee.Error()+"\n")
	}
	if err != nil {
		fail(c, err)
	}
	msg.Write(c, msg.User, []byte("buildpack done\n"))
	slug, err := tempFile()
	if err != nil {
		fail(c, err)
	}
	tw := gzip.NewWriter(slug)
	err = entar(tw, buildDir, c)
	if err != nil {
		fail(c, err)
	}
	err = tw.Close()
	if err != nil {
		fail(c, err)
	}
	slug.Seek(0, 0)
	msg.Write(c, msg.User, []byte("slug built\n"))
	fi, err := slug.Stat()
	if err != nil {
		fail(c, err)
	}
	msg.Write(c, msg.User, []byte(fmt.Sprintf("slug %d bytes\n", fi.Size())))

	_ = slugURL

	procfile := readProcfile()
	if procfile == nil {
		fail(c, "could not read procfile")
	}
	msg.Write(c, msg.Status, []byte{msg.Success})
	err = msg.CopyN(c, msg.File, slug, fi.Size())
	if err != nil {
		panic(err)
	}
	err = msg.Write(c, msg.File, procfile)
	if err != nil {
		panic(err)
	}
	_, err = io.Copy(ioutil.Discard, c) // wait until other side closes
	if err != nil {
		panic(err)
	}
}
예제 #2
0
파일: main.go 프로젝트: kr/hpush
// Communication with builder proceeds as follows:
//   1. write slug url
//   2. write tarball
//   3. read user messages
//   4. read status
//   5. if success:
//      a. read slug
//      b. read procfile
func doBuild(w io.Writer, c net.Conn, slugURL string, bun io.Reader, size int64) (slug *os.File, procfile []byte) {
	err := msg.Write(c, msg.File, []byte(slugURL))
	if err != nil {
		log.Println("msg.Write:", err)
		fmt.Fprintln(w, "could not write slug url", err)
		fmt.Fprintln(w, "internal error")
		return nil, nil
	}
	err = msg.CopyN(c, msg.File, bun, size)
	if err != nil {
		log.Println("msg.CopyN:", err)
		fmt.Fprintln(w, "internal error")
		return nil, nil
	}
	t, m, err := msg.ReadFull(c)
	if err != nil {
		log.Println("msg.ReadFull:", err)
		fmt.Fprintln(w, "internal error")
		return nil, nil
	}
	fprintf(w, "starting build\n")
	for t == msg.User {
		w.Write(m)
		flush(w)
		t, m, err = msg.ReadFull(c)
		if err != nil {
			log.Println("msg.ReadFull:", err)
			fprintf(w, "\ninternal error\n")
			return nil, nil
		}
	}
	if t != msg.Status {
		log.Println("unexpected msg type", t)
		fprintf(w, "\ninternal error\n")
		return nil, nil
	}
	if m[0] == msg.Success {
		fprintf(w, "build ok\n")
		r, err1 := msg.ReadFile(c)
		if err1 != nil {
			log.Println("msg.ReadFile", err1)
			fprintf(w, "internal error\n")
			return nil, nil
		}
		slug, err = spool(r)
		if err != nil {
			log.Println("spool", err)
			fprintf(w, "internal error\n")
			return nil, nil
		}
		t, procfile, err = msg.ReadFull(c)
		if t != msg.File {
			log.Printf("expected file, got %d", t)
			fprintf(w, "internal error\n")
			return nil, nil
		}
	} else {
		fprintf(w, "\nbuild failed\n")
	}
	return slug, procfile
}