<commit_before>package topgun_test

import (
	"fmt"
	"strings"
	"time"

	_ "github.com/lib/pq"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe(":life Garbage collecting resource cache volumes", func() {
	Describe("A resource that was removed from pipeline", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			Expect(volumesByResourceType("time")).To(HaveLen(1))

			By("updating pipeline and removing resource")
			fly("set-pipeline", "-n", "-c", "pipelines/task-waiting.yml", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() int {
				return len(volumesByResourceType("time"))
			}, 5*time.Minute, 10*time.Second).Should(BeZero())
		})
	})

	Describe("A resource that was updated", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "time:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))

			By("updating pipeline and removing resource")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() []string {
				return volumesByResourceType("time")
			}, 5*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))
		})
	})

	Describe("A resource in paused pipeline", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			resourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "time:") {
					resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
				}
			}
			Expect(resourceVolumeHandles).To(HaveLen(1))

			By("pausing the pipeline")
			fly("pause-pipeline", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() int {
				return len(volumesByResourceType("time"))
			}, 5*time.Minute, 10*time.Second).Should(BeZero())
		})
	})

	Describe("a resource that has new versions", func() {
		var (
			gitRepoURI string
			gitRepo    GitRepo
		)

		BeforeEach(func() {
			if !strings.Contains(string(bosh("releases").Out.Contents()), "git-server") {
				Skip("git-server release not uploaded")
			}

			Deploy("deployments/single-vm.yml", "-o", "operations/add-git-server.yml")

			gitRepoURI = fmt.Sprintf("git://%s/some-repo", JobInstance("git_server").IP)
			gitRepo = NewGitRepo(gitRepoURI)
		})

		AfterEach(func() {
			gitRepo.Cleanup()
		})

		It("has its old resource cache, old resource cache uses and old resource cache volumes cleared out", func() {
			By("creating an initial resource version")
			gitRepo.CommitAndPush()

			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-git-resource.yml", "-p", "volume-gc-test", "-v", "some-repo-uri="+gitRepoURI)

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))

			By("creating a new resource version")
			gitRepo.CommitAndPush()

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("eventually expiring the resource cache volume")
			Eventually(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 10*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))
		})
	})

	Describe("resource cache is not reaped when being used by a build", func() {
		var (
			gitRepoURI string
			gitRepo    GitRepo
		)

		BeforeEach(func() {
			if !strings.Contains(string(bosh("releases").Out.Contents()), "git-server") {
				Skip("git-server release not uploaded")
			}

			Deploy("deployments/single-vm-fast-gc.yml", "-o", "operations/add-git-server.yml")

			gitRepoURI = fmt.Sprintf("git://%s/some-repo", JobInstance("git_server").IP)
			gitRepo = NewGitRepo(gitRepoURI)
		})

		AfterEach(func() {
			gitRepo.Cleanup()
		})

		It("finds the resource cache volumes throughout duration of build", func() {
			By("creating an initial resource version")
			gitRepo.CommitAndPush()

			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-git-resource-and-wait.yml", "-p", "volume-gc-test", "-v", "some-repo-uri="+gitRepoURI)

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			watchSession := spawnFly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")
			Eventually(watchSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))

			By("creating a new resource version")
			gitRepo.CommitAndPush()

			By("not expiring the resource cache volume")
			Consistently(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 2*time.Minute).Should(ContainElement(originalResourceVolumeHandles[0]))

			By("hijacking the build to tell it to finish")
			hijackSession := spawnFly(
				"hijack",
				"-j", "volume-gc-test/simple-job",
				"-s", "wait",
				"touch", "/tmp/stop-waiting",
			)
			<-hijackSession.Exited
			Expect(hijackSession.ExitCode()).To(Equal(0))

			By("waiting for the build to exit")
			Eventually(watchSession, 1*time.Minute).Should(gbytes.Say("done"))
			<-watchSession.Exited
			Expect(watchSession.ExitCode()).To(Equal(0))

			By("eventually expiring the resource cache volume")
			Eventually(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 10*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))
		})
	})
})
<commit_msg>add test for volumes of a resoure persisting<commit_after>package topgun_test

import (
	"fmt"
	"strings"
	"time"

	_ "github.com/lib/pq"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe(":life Garbage collecting resource cache volumes", func() {
	Describe("A resource that was removed from pipeline", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			Expect(volumesByResourceType("time")).To(HaveLen(1))

			By("updating pipeline and removing resource")
			fly("set-pipeline", "-n", "-c", "pipelines/task-waiting.yml", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() int {
				return len(volumesByResourceType("time"))
			}, 5*time.Minute, 10*time.Second).Should(BeZero())
		})
	})

	Describe("A resource that was updated", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "time:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))

			By("updating pipeline and removing resource")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() []string {
				return volumesByResourceType("time")
			}, 5*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))
		})
	})

	Describe("A resource in paused pipeline", func() {
		BeforeEach(func() {
			Deploy("deployments/single-vm.yml")
		})

		It("has its resource cache, resource cache uses and resource cache volumes cleared out", func() {
			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-task-changing-resource.yml", "-p", "volume-gc-test")

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			resourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "time:") {
					resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
				}
			}
			Expect(resourceVolumeHandles).To(HaveLen(1))

			By("pausing the pipeline")
			fly("pause-pipeline", "-p", "volume-gc-test")

			By("eventually expiring the resource cache volumes")
			Eventually(func() int {
				return len(volumesByResourceType("time"))
			}, 5*time.Minute, 10*time.Second).Should(BeZero())
		})
	})

	Describe("a resource that has new versions", func() {
		var (
			gitRepoURI string
			gitRepo    GitRepo
		)

		BeforeEach(func() {
			if !strings.Contains(string(bosh("releases").Out.Contents()), "git-server") {
				Skip("git-server release not uploaded")
			}

			Deploy("deployments/single-vm.yml", "-o", "operations/add-git-server.yml")

			gitRepoURI = fmt.Sprintf("git://%s/some-repo", JobInstance("git_server").IP)
			gitRepo = NewGitRepo(gitRepoURI)
		})

		AfterEach(func() {
			gitRepo.Cleanup()
		})

		It("has its old resource cache, old resource cache uses and old resource cache volumes cleared out", func() {
			By("creating an initial resource version")
			gitRepo.CommitAndPush()

			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-git-resource.yml", "-p", "volume-gc-test", "-v", "some-repo-uri="+gitRepoURI)

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))

			By("creating a new resource version")
			gitRepo.CommitAndPush()

			By("triggering the job")
			fly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")

			By("eventually expiring the resource cache volume")
			Eventually(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 10*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))
		})
	})

	Describe("resource cache is not reaped when being used by a build", func() {
		var (
			gitRepoURI string
			gitRepo    GitRepo
		)

		BeforeEach(func() {
			if !strings.Contains(string(bosh("releases").Out.Contents()), "git-server") {
				Skip("git-server release not uploaded")
			}

			Deploy("deployments/single-vm-fast-gc.yml", "-o", "operations/add-git-server.yml")

			gitRepoURI = fmt.Sprintf("git://%s/some-repo", JobInstance("git_server").IP)
			gitRepo = NewGitRepo(gitRepoURI)
		})

		AfterEach(func() {
			gitRepo.Cleanup()
		})

		FIt("finds the resource cache volumes throughout duration of build", func() {
			By("creating an initial resource version")
			gitRepo.CommitAndPush()

			By("setting pipeline that creates resource cache")
			fly("set-pipeline", "-n", "-c", "pipelines/get-git-resource-and-wait.yml", "-p", "volume-gc-test", "-v", "some-repo-uri="+gitRepoURI)

			By("unpausing the pipeline")
			fly("unpause-pipeline", "-p", "volume-gc-test")

			By("triggering the job")
			watchSession := spawnFly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")
			Eventually(watchSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

			By("getting the resource cache volumes")
			volumes := flyTable("volumes")
			originalResourceVolumeHandles := []string{}
			for _, volume := range volumes {
				if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
					originalResourceVolumeHandles = append(originalResourceVolumeHandles, volume["handle"])
				}
			}
			Expect(originalResourceVolumeHandles).To(HaveLen(1))
			//
			By("creating a new resource version")
			gitRepo.CommitAndPush()
			//
			By("not expiring the resource cache volume for the ongoing build")
			Consistently(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 5*time.Second).Should(ContainElement(originalResourceVolumeHandles[0]))

			By("hijacking the build to tell it to finish")
			hijackSession := spawnFly(
				"hijack",
				"-j", "volume-gc-test/simple-job",
				"-s", "wait",
				"touch", "/tmp/stop-waiting",
			)
			<-hijackSession.Exited
			Expect(hijackSession.ExitCode()).To(Equal(0))

			By("waiting for the build to exit")
			Eventually(watchSession, 1*time.Minute).Should(gbytes.Say("done"))
			<-watchSession.Exited
			Expect(watchSession.ExitCode()).To(Equal(0))

			By("triggering the job")
			hijackSession = spawnFly("trigger-job", "-w", "-j", "volume-gc-test/simple-job")
			Eventually(watchSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

			By("eventually expiring the resource cache volume")
			Eventually(func() []string {
				volumes := flyTable("volumes")
				resourceVolumeHandles := []string{}
				fmt.Println(volumes)
				for _, volume := range volumes {
					if volume["type"] == "resource" && strings.HasPrefix(volume["identifier"], "ref:") {
						resourceVolumeHandles = append(resourceVolumeHandles, volume["handle"])
					}
				}
				return resourceVolumeHandles
			}, 1*time.Minute, 10*time.Second).ShouldNot(ContainElement(originalResourceVolumeHandles[0]))

			By("hijacking the build to tell it to finish")
			hijackSession = spawnFly(
				"hijack",
				"-j", "volume-gc-test/simple-job",
				"-s", "wait",
				"touch", "/tmp/stop-waiting",
			)
			<-hijackSession.Exited
			Expect(hijackSession.ExitCode()).To(Equal(0))

			By("waiting for the build to exit")
			Eventually(watchSession, 1*time.Minute).Should(gbytes.Say("done"))
			<-watchSession.Exited
			Expect(watchSession.ExitCode()).To(Equal(0))

		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libfs

import (
	"io"
	"sync/atomic"

	"github.com/keybase/kbfs/libkbfs"
	"github.com/pkg/errors"
	billy "gopkg.in/src-d/go-billy.v3"
)

// File is a wrapper around a libkbfs.Node that implements the
// billy.File interface.
type File struct {
	fs       *FS
	filename string
	node     libkbfs.Node
	readOnly bool
	offset   int64
}

var _ billy.File = (*File)(nil)

// Name implements the billy.File interface for File.
func (f *File) Name() string {
	return f.filename
}

func (f *File) updateOffset(origOffset, advanceBytes int64) {
	// If there are two concurrent Write calls at the same time, it's
	// not well-defined what the offset should be after.  Just set it
	// to what this call thinks it should be and let the application
	// sort things out.
	_ = atomic.SwapInt64(&f.offset, origOffset+advanceBytes)
}

// Write implements the billy.File interface for File.
func (f *File) Write(p []byte) (n int, err error) {
	if f.readOnly {
		return 0, errors.New("Trying to write a read-only file")
	}

	origOffset := atomic.LoadInt64(&f.offset)
	err = f.fs.config.KBFSOps().Write(f.fs.ctx, f.node, p, origOffset)
	if err != nil {
		return 0, err
	}

	f.updateOffset(origOffset, int64(len(p)))
	return len(p), nil
}

// Read implements the billy.File interface for File.
func (f *File) Read(p []byte) (n int, err error) {
	f.fs.log.CDebugf(f.fs.ctx, "Read %d bytes at current offset", len(p))

	origOffset := atomic.LoadInt64(&f.offset)
	readBytes, err := f.fs.config.KBFSOps().Read(
		f.fs.ctx, f.node, p, origOffset)
	if err != nil {
		return 0, err
	}

	if readBytes == 0 {
		return 0, io.EOF
	}

	f.updateOffset(origOffset, readBytes)
	return int(readBytes), nil
}

// ReadAt implements the billy.File interface for File.
func (f *File) ReadAt(p []byte, off int64) (n int, err error) {
	f.fs.log.CDebugf(f.fs.ctx, "Read %d bytes at offset %d", len(p), off)

	// ReadAt doesn't affect the underlying offset.
	readBytes, err := f.fs.config.KBFSOps().Read(f.fs.ctx, f.node, p, off)
	if err != nil {
		return 0, err
	}
	if int(readBytes) < len(p) {
		// ReadAt is more strict than Read.
		return 0, errors.Errorf("Could only read %d bytes", readBytes)
	}

	return int(readBytes), nil
}

// Seek implements the billy.File interface for File.
func (f *File) Seek(offset int64, whence int) (n int64, err error) {
	f.fs.log.CDebugf(f.fs.ctx, "Seek %d bytes (whence=%d)", offset, whence)
	defer func() {
		f.fs.deferLog.CDebugf(f.fs.ctx, "Seek done: %+v", err)
	}()

	newOffset := offset
	switch whence {
	case io.SeekStart:
	case io.SeekCurrent:
		origOffset := atomic.LoadInt64(&f.offset)
		newOffset = origOffset + offset
	case io.SeekEnd:
		ei, err := f.fs.config.KBFSOps().Stat(f.fs.ctx, f.node)
		if err != nil {
			return 0, err
		}
		newOffset = int64(ei.Size) + offset
	}
	if newOffset < 0 {
		return 0, errors.Errorf("Cannot seek to offset %d", newOffset)
	}

	_ = atomic.SwapInt64(&f.offset, newOffset)
	return newOffset, nil
}

// Close implements the billy.File interface for File.
func (f *File) Close() error {
	f.node = nil
	return nil
}
<commit_msg>libfs: remove file debugging messages<commit_after>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libfs

import (
	"io"
	"sync/atomic"

	"github.com/keybase/kbfs/libkbfs"
	"github.com/pkg/errors"
	billy "gopkg.in/src-d/go-billy.v3"
)

// File is a wrapper around a libkbfs.Node that implements the
// billy.File interface.
type File struct {
	fs       *FS
	filename string
	node     libkbfs.Node
	readOnly bool
	offset   int64
}

var _ billy.File = (*File)(nil)

// Name implements the billy.File interface for File.
func (f *File) Name() string {
	return f.filename
}

func (f *File) updateOffset(origOffset, advanceBytes int64) {
	// If there are two concurrent Write calls at the same time, it's
	// not well-defined what the offset should be after.  Just set it
	// to what this call thinks it should be and let the application
	// sort things out.
	_ = atomic.SwapInt64(&f.offset, origOffset+advanceBytes)
}

// Write implements the billy.File interface for File.
func (f *File) Write(p []byte) (n int, err error) {
	if f.readOnly {
		return 0, errors.New("Trying to write a read-only file")
	}

	origOffset := atomic.LoadInt64(&f.offset)
	err = f.fs.config.KBFSOps().Write(f.fs.ctx, f.node, p, origOffset)
	if err != nil {
		return 0, err
	}

	f.updateOffset(origOffset, int64(len(p)))
	return len(p), nil
}

// Read implements the billy.File interface for File.
func (f *File) Read(p []byte) (n int, err error) {
	origOffset := atomic.LoadInt64(&f.offset)
	readBytes, err := f.fs.config.KBFSOps().Read(
		f.fs.ctx, f.node, p, origOffset)
	if err != nil {
		return 0, err
	}

	if readBytes == 0 {
		return 0, io.EOF
	}

	f.updateOffset(origOffset, readBytes)
	return int(readBytes), nil
}

// ReadAt implements the billy.File interface for File.
func (f *File) ReadAt(p []byte, off int64) (n int, err error) {
	// ReadAt doesn't affect the underlying offset.
	readBytes, err := f.fs.config.KBFSOps().Read(f.fs.ctx, f.node, p, off)
	if err != nil {
		return 0, err
	}
	if int(readBytes) < len(p) {
		// ReadAt is more strict than Read.
		return 0, errors.Errorf("Could only read %d bytes", readBytes)
	}

	return int(readBytes), nil
}

// Seek implements the billy.File interface for File.
func (f *File) Seek(offset int64, whence int) (n int64, err error) {
	newOffset := offset
	switch whence {
	case io.SeekStart:
	case io.SeekCurrent:
		origOffset := atomic.LoadInt64(&f.offset)
		newOffset = origOffset + offset
	case io.SeekEnd:
		ei, err := f.fs.config.KBFSOps().Stat(f.fs.ctx, f.node)
		if err != nil {
			return 0, err
		}
		newOffset = int64(ei.Size) + offset
	}
	if newOffset < 0 {
		return 0, errors.Errorf("Cannot seek to offset %d", newOffset)
	}

	_ = atomic.SwapInt64(&f.offset, newOffset)
	return newOffset, nil
}

// Close implements the billy.File interface for File.
func (f *File) Close() error {
	f.node = nil
	return nil
}
<|endoftext|>


<commit_before>package main

import "github.com/nsf/gothic"
import "math/big"

var args [2]*big.Int
var lastOp string
var afterOp = true

func applyOp(op string, ir *gothic.Interpreter) {
	var num string
	ir.EvalAs(&num, "set calcText")
	if args[0] == nil {
		if op != "=" {
			args[0] = big.NewInt(0)
			args[0].SetString(num, 10)
		}
	} else {
		args[1] = big.NewInt(0)
		args[1].SetString(num, 10)
	}

	afterOp = true

	if args[1] == nil {
		lastOp = op
		return
	}

	switch lastOp {
	case "+":
		args[0] = args[0].Add(args[0], args[1])
	case "-":
		args[0] = args[0].Sub(args[0], args[1])
	case "/":
		args[0] = args[0].Div(args[0], args[1])
	case "*":
		args[0] = args[0].Mul(args[0], args[1])
	}

	lastOp = op
	args[1] = nil

	ir.Eval("set calcText %{}", args[0])
	if op == "=" {
		args[0] = nil
	}
}

func main() {
	ir := gothic.NewInterpreter(`
set lastOp {}
set calcText 0
wm title . "GoCalculator"

ttk::frame .f
ttk::entry .f.lastop -textvariable lastOp -justify center -state readonly -width 3
ttk::entry .f.entry -textvariable calcText -justify right -state readonly

grid .f.lastop .f.entry -sticky we
grid columnconfigure .f 0 -weight 0
grid columnconfigure .f 1 -weight 1

ttk::button .0 -text 0 -command { appendNum 0 }
ttk::button .1 -text 1 -command { appendNum 1 }
ttk::button .2 -text 2 -command { appendNum 2 }
ttk::button .3 -text 3 -command { appendNum 3 }
ttk::button .4 -text 4 -command { appendNum 4 }
ttk::button .5 -text 5 -command { appendNum 5 }
ttk::button .6 -text 6 -command { appendNum 6 }
ttk::button .7 -text 7 -command { appendNum 7 }
ttk::button .8 -text 8 -command { appendNum 8 }
ttk::button .9 -text 9 -command { appendNum 9 }
ttk::button .pm    -text +/- -command plusMinus
ttk::button .clear -text C -command clearAll
ttk::button .eq    -text = -command { applyOp = }
ttk::button .plus  -text + -command { applyOp + }
ttk::button .minus -text - -command { applyOp - }
ttk::button .mul   -text * -command { applyOp * }
ttk::button .div   -text / -command { applyOp / }

grid .f -   -      .div   -sticky nwes
grid .7 .8  .9     .mul   -sticky nwes
grid .4 .5  .6     .minus -sticky nwes
grid .1 .2  .3     .plus  -sticky nwes
grid .0 .pm .clear .eq    -sticky nwes

grid configure .f -sticky wes

foreach w [winfo children .] {grid configure $w -padx 3 -pady 3}

grid rowconfigure . 0 -weight 0
foreach i {1 2 3 4} { grid rowconfigure . $i -weight 1 }
foreach i {0 1 2 3} { grid columnconfigure . $i -weight 1 }

bind . 0             { appendNum 0 }
bind . <KP_Insert>   { appendNum 0 }
bind . 1             { appendNum 1 }
bind . <KP_End>      { appendNum 1 }
bind . 2             { appendNum 2 }
bind . <KP_Down>     { appendNum 2 }
bind . 3             { appendNum 3 }
bind . <KP_Next>     { appendNum 3 }
bind . 4             { appendNum 4 }
bind . <KP_Left>     { appendNum 4 }
bind . 5             { appendNum 5 }
bind . <KP_Begin>    { appendNum 5 }
bind . 6             { appendNum 6 }
bind . <KP_Right>    { appendNum 6 }
bind . 7             { appendNum 7 }
bind . <KP_Home>     { appendNum 7 }
bind . 8             { appendNum 8 }
bind . <KP_Up>       { appendNum 8 }
bind . 9             { appendNum 9 }
bind . <KP_Prior>    { appendNum 9 }
bind . +             { applyOp + }
bind . <KP_Add>      { applyOp + }
bind . -             { applyOp - }
bind . <KP_Subtract> { applyOp - }
bind . *             { applyOp * }
bind . <KP_Multiply> { applyOp * }
bind . /             { applyOp / }
bind . <KP_Divide>   { applyOp / }
bind . <Return>      { applyOp = }
bind . <KP_Enter>    { applyOp = }
bind . <BackSpace>   { clearAll }
	`)

	ir.RegisterCommand("appendNum", func(n string) {
		if afterOp {
			afterOp = false
			ir.Eval("set calcText {}")
		}
		ir.Eval("append calcText %{}", n)
	})

	ir.RegisterCommand("applyOp", func(op string) {
		if afterOp && lastOp != "=" {
			return
		}
		applyOp(op, ir)
		ir.Eval("set lastOp %{}", lastOp)
	})

	ir.RegisterCommand("clearAll", func() {
		args[0] = nil
		args[1] = nil
		afterOp = true
		lastOp = ""
		ir.Eval("set lastOp {}; set calcText 0")
	})

	ir.RegisterCommand("plusMinus", func() {
		var text string
		ir.EvalAs(&text, "set calcText")
		if len(text) == 0 || text[0] == '0' {
			return
		}

		if text[0] == '-' {
			ir.Eval("set calcText %{}", text[1:])
		} else {
			ir.Eval("set calcText -%{}", text)
		}
	})

	<-ir.Done
}
<commit_msg>Typo. Display frame should be sticky to east and west, not south.<commit_after>package main

import "github.com/nsf/gothic"
import "math/big"

var args [2]*big.Int
var lastOp string
var afterOp = true

func applyOp(op string, ir *gothic.Interpreter) {
	var num string
	ir.EvalAs(&num, "set calcText")
	if args[0] == nil {
		if op != "=" {
			args[0] = big.NewInt(0)
			args[0].SetString(num, 10)
		}
	} else {
		args[1] = big.NewInt(0)
		args[1].SetString(num, 10)
	}

	afterOp = true

	if args[1] == nil {
		lastOp = op
		return
	}

	switch lastOp {
	case "+":
		args[0] = args[0].Add(args[0], args[1])
	case "-":
		args[0] = args[0].Sub(args[0], args[1])
	case "/":
		args[0] = args[0].Div(args[0], args[1])
	case "*":
		args[0] = args[0].Mul(args[0], args[1])
	}

	lastOp = op
	args[1] = nil

	ir.Eval("set calcText %{}", args[0])
	if op == "=" {
		args[0] = nil
	}
}

func main() {
	ir := gothic.NewInterpreter(`
set lastOp {}
set calcText 0
wm title . "GoCalculator"

ttk::frame .f
ttk::entry .f.lastop -textvariable lastOp -justify center -state readonly -width 3
ttk::entry .f.entry -textvariable calcText -justify right -state readonly

grid .f.lastop .f.entry -sticky we
grid columnconfigure .f 0 -weight 0
grid columnconfigure .f 1 -weight 1

ttk::button .0 -text 0 -command { appendNum 0 }
ttk::button .1 -text 1 -command { appendNum 1 }
ttk::button .2 -text 2 -command { appendNum 2 }
ttk::button .3 -text 3 -command { appendNum 3 }
ttk::button .4 -text 4 -command { appendNum 4 }
ttk::button .5 -text 5 -command { appendNum 5 }
ttk::button .6 -text 6 -command { appendNum 6 }
ttk::button .7 -text 7 -command { appendNum 7 }
ttk::button .8 -text 8 -command { appendNum 8 }
ttk::button .9 -text 9 -command { appendNum 9 }
ttk::button .pm    -text +/- -command plusMinus
ttk::button .clear -text C -command clearAll
ttk::button .eq    -text = -command { applyOp = }
ttk::button .plus  -text + -command { applyOp + }
ttk::button .minus -text - -command { applyOp - }
ttk::button .mul   -text * -command { applyOp * }
ttk::button .div   -text / -command { applyOp / }

grid .f -   -      .div   -sticky nwes
grid .7 .8  .9     .mul   -sticky nwes
grid .4 .5  .6     .minus -sticky nwes
grid .1 .2  .3     .plus  -sticky nwes
grid .0 .pm .clear .eq    -sticky nwes

grid configure .f -sticky we

foreach w [winfo children .] {grid configure $w -padx 3 -pady 3}

grid rowconfigure . 0 -weight 0
foreach i {1 2 3 4} { grid rowconfigure . $i -weight 1 }
foreach i {0 1 2 3} { grid columnconfigure . $i -weight 1 }

bind . 0             { appendNum 0 }
bind . <KP_Insert>   { appendNum 0 }
bind . 1             { appendNum 1 }
bind . <KP_End>      { appendNum 1 }
bind . 2             { appendNum 2 }
bind . <KP_Down>     { appendNum 2 }
bind . 3             { appendNum 3 }
bind . <KP_Next>     { appendNum 3 }
bind . 4             { appendNum 4 }
bind . <KP_Left>     { appendNum 4 }
bind . 5             { appendNum 5 }
bind . <KP_Begin>    { appendNum 5 }
bind . 6             { appendNum 6 }
bind . <KP_Right>    { appendNum 6 }
bind . 7             { appendNum 7 }
bind . <KP_Home>     { appendNum 7 }
bind . 8             { appendNum 8 }
bind . <KP_Up>       { appendNum 8 }
bind . 9             { appendNum 9 }
bind . <KP_Prior>    { appendNum 9 }
bind . +             { applyOp + }
bind . <KP_Add>      { applyOp + }
bind . -             { applyOp - }
bind . <KP_Subtract> { applyOp - }
bind . *             { applyOp * }
bind . <KP_Multiply> { applyOp * }
bind . /             { applyOp / }
bind . <KP_Divide>   { applyOp / }
bind . <Return>      { applyOp = }
bind . <KP_Enter>    { applyOp = }
bind . <BackSpace>   { clearAll }
	`)

	ir.RegisterCommand("appendNum", func(n string) {
		if afterOp {
			afterOp = false
			ir.Eval("set calcText {}")
		}
		ir.Eval("append calcText %{}", n)
	})

	ir.RegisterCommand("applyOp", func(op string) {
		if afterOp && lastOp != "=" {
			return
		}
		applyOp(op, ir)
		ir.Eval("set lastOp %{}", lastOp)
	})

	ir.RegisterCommand("clearAll", func() {
		args[0] = nil
		args[1] = nil
		afterOp = true
		lastOp = ""
		ir.Eval("set lastOp {}; set calcText 0")
	})

	ir.RegisterCommand("plusMinus", func() {
		var text string
		ir.EvalAs(&text, "set calcText")
		if len(text) == 0 || text[0] == '0' {
			return
		}

		if text[0] == '-' {
			ir.Eval("set calcText %{}", text[1:])
		} else {
			ir.Eval("set calcText -%{}", text)
		}
	})

	<-ir.Done
}
<|endoftext|>


<commit_before>package lint

import (
	"bytes"
	"errors"
	"fmt"
	"strings"
)

var metadataLinebreakRule = &MetaData{
	Name: "linebreak",

	// this rule should called before all rules
	rank: 0,
}

var (
	ErrUnknownLinebreakStyle = errors.New("unknown line break style")
)

type LinebreakStyle []byte

var (
	UnixStyleLinebreak    = LinebreakStyle{'\n'}
	WindowsStyleLinebreak = LinebreakStyle{'\r', '\n'}
)

func NewLinebreakStyle(str string) (LinebreakStyle, error) {
	switch strings.ToLower(str) {
	case "lf":
		return UnixStyleLinebreak, nil
	case "crlf":
		return WindowsStyleLinebreak, nil
	}
	return nil, ErrUnknownLinebreakStyle
}

func (s LinebreakStyle) text() string {
	switch {
	case bytes.Equal(s, UnixStyleLinebreak):
		return "LF"
	case bytes.Equal(s, WindowsStyleLinebreak):
		return "CRLF"
	}
	return ""
}

type LinebreakRule struct {
	Style LinebreakStyle
}

func NewLinebreakRule(ops map[string]interface{}) (Rule, error) {
	rule := &LinebreakRule{}

	if v, ok := ops["style"]; ok {
		if value, ok := v.(string); ok {
			style, err := NewLinebreakStyle(value)
			if err != nil {
				return nil, fmt.Errorf("linebreak.style is invalid: %v: %q", err, value)
			}
			rule.Style = style
		} else {
			return nil, fmt.Errorf("linebreak.style is invalid: %v: %q", ErrUnknownLinebreakStyle, value)
		}
	}

	return rule, nil
}

func (r *LinebreakRule) New(ops map[string]interface{}) (Rule, error) {
	return NewLinebreakRule(ops)
}

func (r *LinebreakRule) MetaData() *MetaData {
	return metadataLinebreakRule
}

func (r *LinebreakRule) Lint(s []byte) (*Result, error) {
	res := NewResult()

	formatTarget := detectLinebreakStyle(s)
	if bytes.Equal(formatTarget, r.Style) {
		res.Set(s)
		return res, nil
	}

	errmsg := fmt.Sprintf(
		`Expected linebreaks to be %s but found %s`,
		r.Style.text(),
		formatTarget.text(),
	)
	res.AddReport(-1, -1, errmsg)
	res.Set(bytes.Replace(s, formatTarget, r.Style, -1))

	return res, nil
}

func detectLinebreakStyle(bs []byte) LinebreakStyle {
	for _, b := range bs {
		if b == '\r' {
			return WindowsStyleLinebreak
		}
	}

	return UnixStyleLinebreak
}

func init() {
	definedRules.Set(&LinebreakRule{})
}
<commit_msg>Use String() instead of text()<commit_after>package lint

import (
	"bytes"
	"errors"
	"fmt"
	"strings"
)

var metadataLinebreakRule = &MetaData{
	Name: "linebreak",

	// this rule should called before all rules
	rank: 0,
}

var (
	ErrUnknownLinebreakStyle = errors.New("unknown line break style")
)

type LinebreakStyle []byte

var (
	UnixStyleLinebreak    = LinebreakStyle{'\n'}
	WindowsStyleLinebreak = LinebreakStyle{'\r', '\n'}
)

func NewLinebreakStyle(str string) (LinebreakStyle, error) {
	switch strings.ToLower(str) {
	case "lf":
		return UnixStyleLinebreak, nil
	case "crlf":
		return WindowsStyleLinebreak, nil
	}
	return nil, ErrUnknownLinebreakStyle
}

func (s LinebreakStyle) String() string {
	switch {
	case bytes.Equal(s, UnixStyleLinebreak):
		return "LF"
	case bytes.Equal(s, WindowsStyleLinebreak):
		return "CRLF"
	}
	return ""
}

type LinebreakRule struct {
	Style LinebreakStyle
}

func NewLinebreakRule(ops map[string]interface{}) (Rule, error) {
	rule := &LinebreakRule{}

	if v, ok := ops["style"]; ok {
		if value, ok := v.(string); ok {
			style, err := NewLinebreakStyle(value)
			if err != nil {
				return nil, fmt.Errorf("linebreak.style is invalid: %v: %q", err, value)
			}
			rule.Style = style
		} else {
			return nil, fmt.Errorf("linebreak.style is invalid: %v: %q", ErrUnknownLinebreakStyle, value)
		}
	}

	return rule, nil
}

func (r *LinebreakRule) New(ops map[string]interface{}) (Rule, error) {
	return NewLinebreakRule(ops)
}

func (r *LinebreakRule) MetaData() *MetaData {
	return metadataLinebreakRule
}

func (r *LinebreakRule) Lint(s []byte) (*Result, error) {
	res := NewResult()

	formatTarget := detectLinebreakStyle(s)
	if bytes.Equal(formatTarget, r.Style) {
		res.Set(s)
		return res, nil
	}

	errmsg := fmt.Sprintf(
		`Expected linebreaks to be %s but found %s`,
		r.Style,
		formatTarget,
	)
	res.AddReport(-1, -1, errmsg)
	res.Set(bytes.Replace(s, formatTarget, r.Style, -1))

	return res, nil
}

func detectLinebreakStyle(bs []byte) LinebreakStyle {
	for _, b := range bs {
		if b == '\r' {
			return WindowsStyleLinebreak
		}
	}

	return UnixStyleLinebreak
}

func init() {
	definedRules.Set(&LinebreakRule{})
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker Compose CLI authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package e2e

import (
	"os"
	"strings"
	"testing"

	"gotest.tools/v3/assert"
	"gotest.tools/v3/icmd"

	. "github.com/docker/compose-cli/utils/e2e"
)

func TestCopy(t *testing.T) {
	c := NewParallelE2eCLI(t, binDir)

	const projectName = "copy_e2e"

	t.Cleanup(func() {
		c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "--project-name", projectName, "down")

		os.Remove("./fixtures/cp-test/from-default.txt")
		os.Remove("./fixtures/cp-test/from-indexed.txt")
		os.RemoveAll("./fixtures/cp-test/cp-folder2")
	})

	t.Run("start service", func(t *testing.T) {
		c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "--project-name", projectName, "up", "--scale", "nginx=5", "-d")
	})

	t.Run("make sure service is running", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-p", projectName, "ps")
		res.Assert(t, icmd.Expected{Out: `nginx               running`})
	})

	t.Run("copy to container copies the file to the first container by default", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/default.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		res = c.RunDockerOrExitError("exec", projectName+"_nginx_2", "cat", "/tmp/default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 1})
	})

	t.Run("copy to container with a given index copies the file to the given container", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--index=3", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_3", "cat", "/tmp/indexed.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		res = c.RunDockerOrExitError("exec", projectName+"_nginx_2", "cat", "/tmp/indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 1})
	})

	t.Run("copy to container with the all flag copies the file to all containers", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--all", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/all.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		output = c.RunDockerCmd("exec", projectName+"_nginx_2", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		output = c.RunDockerCmd("exec", projectName+"_nginx_3", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)
	})

	t.Run("copy from a container copies the file to the host from the first container by default", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/from-default.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world`, string(data))
	})

	t.Run("copy from a container with a given index copies the file to host", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--index=3", "nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/from-indexed.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world`, string(data))
	})

	t.Run("copy to and from a container also work with folder", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "./fixtures/cp-test/cp-folder", "nginx:/tmp")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world from folder`), output)

		res = c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/cp-folder2/cp-me.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world from folder`, string(data))
	})
}
<commit_msg>ignore linter err<commit_after>/*
   Copyright 2020 Docker Compose CLI authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package e2e

import (
	"os"
	"strings"
	"testing"

	"gotest.tools/v3/assert"
	"gotest.tools/v3/icmd"

	. "github.com/docker/compose-cli/utils/e2e"
)

func TestCopy(t *testing.T) {
	c := NewParallelE2eCLI(t, binDir)

	const projectName = "copy_e2e"

	t.Cleanup(func() {
		c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "--project-name", projectName, "down")

		os.Remove("./fixtures/cp-test/from-default.txt") //nolint:errcheck
		os.Remove("./fixtures/cp-test/from-indexed.txt") //nolint:errcheck
		os.RemoveAll("./fixtures/cp-test/cp-folder2")    //nolint:errcheck
	})

	t.Run("start service", func(t *testing.T) {
		c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "--project-name", projectName, "up", "--scale", "nginx=5", "-d")
	})

	t.Run("make sure service is running", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-p", projectName, "ps")
		res.Assert(t, icmd.Expected{Out: `nginx               running`})
	})

	t.Run("copy to container copies the file to the first container by default", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/default.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		res = c.RunDockerOrExitError("exec", projectName+"_nginx_2", "cat", "/tmp/default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 1})
	})

	t.Run("copy to container with a given index copies the file to the given container", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--index=3", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_3", "cat", "/tmp/indexed.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		res = c.RunDockerOrExitError("exec", projectName+"_nginx_2", "cat", "/tmp/indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 1})
	})

	t.Run("copy to container with the all flag copies the file to all containers", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--all", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/all.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		output = c.RunDockerCmd("exec", projectName+"_nginx_2", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)

		output = c.RunDockerCmd("exec", projectName+"_nginx_3", "cat", "/tmp/all.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world`), output)
	})

	t.Run("copy from a container copies the file to the host from the first container by default", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/from-default.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world`, string(data))
	})

	t.Run("copy from a container with a given index copies the file to host", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "--index=3", "nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/from-indexed.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world`, string(data))
	})

	t.Run("copy to and from a container also work with folder", func(t *testing.T) {
		res := c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "./fixtures/cp-test/cp-folder", "nginx:/tmp")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		output := c.RunDockerCmd("exec", projectName+"_nginx_1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout()
		assert.Assert(t, strings.Contains(output, `hello world from folder`), output)

		res = c.RunDockerCmd("compose", "-f", "./fixtures/cp-test/docker-compose.yml", "-p", projectName, "cp", "nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2")
		res.Assert(t, icmd.Expected{ExitCode: 0})

		data, err := os.ReadFile("./fixtures/cp-test/cp-folder2/cp-me.txt")
		assert.NilError(t, err)
		assert.Equal(t, `hello world from folder`, string(data))
	})
}
<|endoftext|>


<commit_before>// Riversist - Monitors network traffic for malicious hosts based on DNSBLs
//
// Copyright 2014 Dolf Schimmel, Freeaqingme.
//
// This Source Code Form is subject to the terms of the two-clause BSD license.
// For its contents, please refer to the LICENSE file.
//
package ipChecker

import (
	"fmt"
	"net"
	"strconv"
	"strings"
)

type ProjectHoneyPotConfig struct {
	Config
	Enabled      bool
	Api_Key      string
	Stale_Period int
	Max_Score    int
}

type ProjectHoneyPotChecker struct {
	IpChecker
	config ProjectHoneyPotConfig
}

func (checker *ProjectHoneyPotChecker) GetName() string {
	return "projectHoneyPot"
}

func (checker *ProjectHoneyPotChecker) IsIpMalicious(ip string, logger Logger) bool {

	if strings.Index(ip, ".") < 0 {
		// As we don't support IPv6 yet, it is all considered HAM
		return false
	}

	split_ip := strings.Split(ip, ".")
	rev_ip := strings.Join([]string{split_ip[3], split_ip[2], split_ip[1], split_ip[0]}, ".")

	host, err := net.LookupHost(fmt.Sprintf("%v.%v.dnsbl.httpbl.org", checker.config.Api_Key, rev_ip))
	if len(host) == 0 {
		logger.Log(LOG_DEBUG, "Received no result from httpbl.org:", err.Error())
		return false
	}

	// Return value: "127", days gone stale, threat score, type (0 search engine, 1 suspicious, 2 harvester, 4 comment spammer)
	ret_octets := strings.Split(host[0], ".")
	if len(ret_octets) != 4 || ret_octets[0] != "127" {
		logger.Log(LOG_INFO, "Invalid return value from httpbl.org:", string(host[0]))
		return false
	}

	conf_stale_period := checker.config.Stale_Period
	conf_max_score := checker.config.Max_Score
	stale_period, _ := strconv.Atoi(ret_octets[1])
	threat_score, _ := strconv.Atoi(ret_octets[2])
	// todo: What to do when stale_period == 0 ?
	score := (conf_stale_period / stale_period) * threat_score

	// Prefer it to be at least conf_stale_period days stale with a score of < conf_max_score
	if stale_period > conf_stale_period {
		logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: stale, stale_period:", strconv.Itoa(stale_period), ", stale_threshold: ", strconv.Itoa(conf_stale_period), " verdict: ham, dnsbl_retval: ", host[0])
		return false
	}

	if score > conf_max_score {
		logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: legit, dnsbl_retval:", host[0])
		return false
	}

	logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: legit, dnsbl_retval:", host[0])
	return false

}

func NewProjectHoneyPotChecker(config ProjectHoneyPotConfig) *ProjectHoneyPotChecker {
	ret := new(ProjectHoneyPotChecker)

	ret.config = config
	return ret
}
<commit_msg>Removed two small bugs from project honeypot checker<commit_after>// Riversist - Monitors network traffic for malicious hosts based on DNSBLs
//
// Copyright 2014 Dolf Schimmel, Freeaqingme.
//
// This Source Code Form is subject to the terms of the two-clause BSD license.
// For its contents, please refer to the LICENSE file.
//
package ipChecker

import (
	"fmt"
	"net"
	"strconv"
	"strings"
)

type ProjectHoneyPotConfig struct {
	Config
	Enabled      bool
	Api_Key      string
	Stale_Period int
	Max_Score    int
}

type ProjectHoneyPotChecker struct {
	IpChecker
	config ProjectHoneyPotConfig
}

func (checker *ProjectHoneyPotChecker) GetName() string {
	return "projectHoneyPot"
}

func (checker *ProjectHoneyPotChecker) IsIpMalicious(ip string, logger Logger) bool {

	if strings.Index(ip, ".") < 0 {
		// As we don't support IPv6 yet, it is all considered HAM
		return false
	}

	split_ip := strings.Split(ip, ".")
	rev_ip := strings.Join([]string{split_ip[3], split_ip[2], split_ip[1], split_ip[0]}, ".")

	host, err := net.LookupHost(fmt.Sprintf("%v.%v.dnsbl.httpbl.org", checker.config.Api_Key, rev_ip))
	if len(host) == 0 {
		logger.Log(LOG_DEBUG, "Received no result from httpbl.org:", err.Error())
		return false
	}

	// Return value: "127", days gone stale, threat score, type (0 search engine, 1 suspicious, 2 harvester, 4 comment spammer)
	ret_octets := strings.Split(host[0], ".")
	if len(ret_octets) != 4 || ret_octets[0] != "127" {
		logger.Log(LOG_INFO, "Invalid return value from httpbl.org:", string(host[0]))
		return false
	}

	conf_stale_period := checker.config.Stale_Period
	conf_max_score := checker.config.Max_Score
	stale_period, _ := strconv.Atoi(ret_octets[1])
	threat_score, _ := strconv.Atoi(ret_octets[2])
	if stale_period == 0 {
		stale_period = 1 // Prevent division by zero, still get a decent score
	}
	score := (conf_stale_period / stale_period) * threat_score

	// Prefer it to be at least conf_stale_period days stale with a score of < conf_max_score
	if stale_period > conf_stale_period {
		logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: stale, stale_period:", strconv.Itoa(stale_period), ", stale_threshold: ", strconv.Itoa(conf_stale_period), " verdict: ham, dnsbl_retval: ", host[0])
		return false
	}

	if score > conf_max_score {
		logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: malicious, dnsbl_retval:", host[0])
		return true
	}

	logger.Log(LOG_INFO, "DNSBL: httpbl.org, IP:", ip, ", score:", strconv.Itoa(score), ", threshold:", strconv.Itoa(conf_max_score), ", verdict: legit, dnsbl_retval:", host[0])
	return false

}

func NewProjectHoneyPotChecker(config ProjectHoneyPotConfig) *ProjectHoneyPotChecker {
	ret := new(ProjectHoneyPotChecker)

	ret.config = config
	return ret
}
<|endoftext|>


<commit_before>package local

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sync/atomic"
	"time"

	"github.com/altairsix/pkg/types"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sqs"
)

const (
	Region = "us-west-2"
	Env    = "local"
)

var (
	DynamoDB *dynamodb.DynamoDB
	SNS      *sns.SNS
	SQS      *sqs.SQS
)

var (
	IDFactory types.IDFactory
)

func init() {
	dir, err := filepath.Abs(".")
	if err != nil {
		log.Fatalln(err)
	}

	env := map[string]string{}
	for i := 0; i < 5; i++ {
		dir = filepath.Join(dir, "..")
		filename := filepath.Join(dir, "test.json")
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			continue
		}

		err = json.Unmarshal(data, &env)
		if err != nil {
			log.Fatalln(err)
		}
		break
	}

	for k, v := range env {
		os.Setenv(k, v)
	}

	region := os.Getenv("AWS_DEFAULT_REGION")
	if region == "" {
		region = "us-west-2"
	}

	cfg := &aws.Config{Region: aws.String(region)}
	s, err := session.NewSession(cfg)
	if err != nil {
		log.Fatalln(err)
	}

	DynamoDB = dynamodb.New(s)
	SNS = sns.New(s)
	SQS = sqs.New(s)

	id := time.Now().UnixNano()
	IDFactory = func() types.ID {
		atomic.AddInt64(&id, 1)
		return types.ID(id)
	}
}

func NewID() types.ID {
	return IDFactory.NewID()
}

func NewKey() types.Key {
	return IDFactory.NewKey()
}
<commit_msg>- local package now includes a local context so we don't need to keep creating one<commit_after>package local

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sync/atomic"
	"time"

	"github.com/altairsix/pkg/context"
	"github.com/altairsix/pkg/types"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sqs"
)

const (
	Region = "us-west-2"
	Env    = "local"
)

var (
	Context  context.Kontext = context.Background(Env)
	DynamoDB *dynamodb.DynamoDB
	SNS      *sns.SNS
	SQS      *sqs.SQS
)

var (
	IDFactory types.IDFactory
)

func init() {
	dir, err := filepath.Abs(".")
	if err != nil {
		log.Fatalln(err)
	}

	env := map[string]string{}
	for i := 0; i < 5; i++ {
		dir = filepath.Join(dir, "..")
		filename := filepath.Join(dir, "test.json")
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			continue
		}

		err = json.Unmarshal(data, &env)
		if err != nil {
			log.Fatalln(err)
		}
		break
	}

	for k, v := range env {
		os.Setenv(k, v)
	}

	region := os.Getenv("AWS_DEFAULT_REGION")
	if region == "" {
		region = "us-west-2"
	}

	cfg := &aws.Config{Region: aws.String(region)}
	s, err := session.NewSession(cfg)
	if err != nil {
		log.Fatalln(err)
	}

	DynamoDB = dynamodb.New(s)
	SNS = sns.New(s)
	SQS = sqs.New(s)

	id := time.Now().UnixNano()
	IDFactory = func() types.ID {
		atomic.AddInt64(&id, 1)
		return types.ID(id)
	}
}

func NewID() types.ID {
	return IDFactory.NewID()
}

func NewKey() types.Key {
	return IDFactory.NewKey()
}
<|endoftext|>


<commit_before>package astar

import (
	"container/heap"
	//"fmt"
)

// astar is an A* pathfinding implementation.

// Pather is an interface which allows A* searching on arbitrary objects which
// can represent a weighted graph.
type Pather interface {
	// PathNeighbors returns the direct neighboring nodes of this node which
	// can be pathed to.
	PathNeighbors() []Pather
	// PathNeighborCost calculates the exact movement cost to neighbor nodes.
	PathNeighborCost(to Pather) float64
	// PathEstimatedCost is a heuristic method for estimating movement costs
	// between non-adjacent nodes.
	PathEstimatedCost(to Pather) float64
}

// node is a wrapper to store A* data for a Pather node.
type node struct {
	pather Pather
	cost   float64
	rank   float64
	parent *node
	open   bool
	closed bool
	index  int
}

// nodeMap is a collection of nodes keyed by Pather nodes for quick reference.
type nodeMap map[Pather]*node

// get gets the Pather object wrapped in a node, instantiating if required.
func (nm nodeMap) get_node_from_pather(p Pather) *node {
	n, ok := nm[p]
	if !ok {
		n = &node{
			pather: p,
		}
		nm[p] = n
	}
	return n
}

func expand(nm nodeMap, nq *priorityQueue, curnode *node, dest Pather) {
	for _, neighbor := range curnode.pather.PathNeighbors() {

		cost := curnode.cost + curnode.pather.PathNeighborCost(neighbor)
		neighborNode := nm.get_node_from_pather(neighbor)

		if cost < neighborNode.cost {
			if neighborNode.open {
				heap.Remove(nq, neighborNode.index)
			}
			neighborNode.open = false
			neighborNode.closed = false
		}
		if !neighborNode.open && !neighborNode.closed {
			neighborNode.cost = cost
			neighborNode.open = true
			neighborNode.rank = cost + neighbor.PathEstimatedCost(dest)
			neighborNode.parent = curnode
			heap.Push(nq, neighborNode)
		}
	}
}

// Path calculates a short path and the distance between the two Pather nodes.
//
// If no path is found, found will be false.
func Path(from Pather, to Pather) (path []Pather, distance float64, found bool) {
	fwd_nodemap := nodeMap{}
	fwd_nq := &priorityQueue{} // fwd priq

	heap.Init(fwd_nq)

	fromNode := fwd_nodemap.get_node_from_pather(from)
	fromNode.open = true

	heap.Push(fwd_nq, fromNode)

	for {
		if fwd_nq.Len() == 0 {
			// There's no path, return found false.
			return
		}

		fwd_curnode := heap.Pop(fwd_nq).(*node)
		fwd_curnode.open = false
		fwd_curnode.closed = true
		fwd_pather := fwd_curnode.pather
		//fmt.Println(fwd_curnode)

		if fwd_pather == to {
			// Found a path to the goal.
			//fmt.Println("RES:", fwd_pather)

			p := []Pather{}

			curr := fwd_curnode.parent
			for curr != nil {
				p = append(p, curr.pather)
				//fmt.Println(curr.pather)
				curr = curr.parent
			}

			return p, fwd_curnode.parent.cost, true
		}

		expand(fwd_nodemap, fwd_nq, fwd_curnode, to)

	}
}

// Path calculates a short path and the distance between the two Pather nodes.
//
// If no path is found, found will be false.
func PathBidir(from Pather, to Pather) (path []Pather, distance float64, found bool) {
	fwd_nodemap := nodeMap{}
	fwd_nq := &priorityQueue{} // fwd priq

	rev_nodemap := nodeMap{}
	rev_nq := &priorityQueue{} // rev priq

	heap.Init(fwd_nq)
	heap.Init(rev_nq)

	fromNode := fwd_nodemap.get_node_from_pather(from)
	fromNode.open = true

	toNode := rev_nodemap.get_node_from_pather(to)
	toNode.open = true

	heap.Push(fwd_nq, fromNode)
	heap.Push(rev_nq, toNode)

	for {
		if fwd_nq.Len() == 0 || rev_nq.Len() == 0 {
			// There's no path, return found false.
			return
		}

		fwd_curnode := heap.Pop(fwd_nq).(*node)
		fwd_curnode.open = false
		fwd_curnode.closed = true
		fwd_pather := fwd_curnode.pather
		//fmt.Println(fwd_curnode)

		rev_curnode := heap.Pop(rev_nq).(*node)
		rev_curnode.open = false
		rev_curnode.closed = true
		//rev_pather := rev_curnode.pather
		//fmt.Println(rev_curnode)

		fwd_node_in_rev_map := rev_nodemap.get_node_from_pather(fwd_pather)
		if fwd_node_in_rev_map.closed || fwd_node_in_rev_map.open || fwd_pather == to {
			// Found a path to the goal.
			//fmt.Println("RES:", fwd_node_in_rev_map.closed, fwd_node_in_rev_map.open, fwd_pather) //, rev_pather)

			rp := []Pather{}
			curr := rev_curnode
			for curr != nil {
				rp = append(rp, curr.pather)
				curr = curr.parent
			}

			// reverse the path from touchpoint to "to"
			p := []Pather{}
			for i := len(rp) - 1; i >= 0; i = i - 1 {
				p = append(p, rp[i])
				//fmt.Println(rp[i])
			}
			//fmt.Println("revdone")

			curr = fwd_curnode.parent
			for curr != nil {
				p = append(p, curr.pather)
				//fmt.Println(curr.pather)
				curr = curr.parent
			}

			return p, fwd_curnode.parent.cost + rev_curnode.cost, true
		}

		expand(fwd_nodemap, fwd_nq, fwd_curnode, to)
		expand(rev_nodemap, rev_nq, rev_curnode, from)

	}
}
<commit_msg>bugfix correcting broken paths<commit_after>package astar

import (
	"container/heap"
	//"fmt"
)

// astar is an A* pathfinding implementation.

// Pather is an interface which allows A* searching on arbitrary objects which
// can represent a weighted graph.
type Pather interface {
	// PathNeighbors returns the direct neighboring nodes of this node which
	// can be pathed to.
	PathNeighbors() []Pather
	// PathNeighborCost calculates the exact movement cost to neighbor nodes.
	PathNeighborCost(to Pather) float64
	// PathEstimatedCost is a heuristic method for estimating movement costs
	// between non-adjacent nodes.
	PathEstimatedCost(to Pather) float64
}

// node is a wrapper to store A* data for a Pather node.
type node struct {
	pather Pather
	cost   float64
	rank   float64
	parent *node
	open   bool
	closed bool
	index  int
}

// nodeMap is a collection of nodes keyed by Pather nodes for quick reference.
type nodeMap map[Pather]*node

// get gets the Pather object wrapped in a node, instantiating if required.
func (nm nodeMap) get_node_from_pather(p Pather) *node {
	n, ok := nm[p]
	if !ok {
		n = &node{
			pather: p,
		}
		nm[p] = n
	}
	return n
}

func expand(nm nodeMap, nq *priorityQueue, curnode *node, dest Pather) {
	for _, neighbor := range curnode.pather.PathNeighbors() {

		cost := curnode.cost + curnode.pather.PathNeighborCost(neighbor)
		neighborNode := nm.get_node_from_pather(neighbor)

		if cost < neighborNode.cost {
			if neighborNode.open {
				heap.Remove(nq, neighborNode.index)
			}
			neighborNode.open = false
			neighborNode.closed = false
		}
		if !neighborNode.open && !neighborNode.closed {
			neighborNode.cost = cost
			neighborNode.open = true
			neighborNode.rank = cost + neighbor.PathEstimatedCost(dest)
			neighborNode.parent = curnode
			heap.Push(nq, neighborNode)
		}
	}
}

// Path calculates a short path and the distance between the two Pather nodes.
//
// If no path is found, found will be false.
func Path(from Pather, to Pather) (path []Pather, distance float64, found bool) {
	fwd_nodemap := nodeMap{}
	fwd_nq := &priorityQueue{} // fwd priq

	heap.Init(fwd_nq)

	fromNode := fwd_nodemap.get_node_from_pather(from)
	fromNode.open = true

	heap.Push(fwd_nq, fromNode)

	for {
		if fwd_nq.Len() == 0 {
			// There's no path, return found false.
			return
		}

		fwd_curnode := heap.Pop(fwd_nq).(*node)
		fwd_curnode.open = false
		fwd_curnode.closed = true
		fwd_pather := fwd_curnode.pather
		//fmt.Println(fwd_curnode)

		if fwd_pather == to {
			// Found a path to the goal.
			//fmt.Println("RES:", fwd_pather)

			p := []Pather{}

			curr := fwd_curnode.parent
			for curr != nil {
				p = append(p, curr.pather)
				//fmt.Println(curr.pather)
				curr = curr.parent
			}

			return p, fwd_curnode.parent.cost, true
		}

		expand(fwd_nodemap, fwd_nq, fwd_curnode, to)

	}
}

// Path calculates a short path and the distance between the two Pather nodes.
//
// If no path is found, found will be false.
func PathBidir(from Pather, to Pather) (path []Pather, distance float64, found bool) {
	fwd_nodemap := nodeMap{}
	fwd_nq := &priorityQueue{} // fwd priq

	rev_nodemap := nodeMap{}
	rev_nq := &priorityQueue{} // rev priq

	heap.Init(fwd_nq)
	heap.Init(rev_nq)

	fromNode := fwd_nodemap.get_node_from_pather(from)
	fromNode.open = true

	toNode := rev_nodemap.get_node_from_pather(to)
	toNode.open = true

	heap.Push(fwd_nq, fromNode)
	heap.Push(rev_nq, toNode)

	for {
		if fwd_nq.Len() == 0 || rev_nq.Len() == 0 {
			// There's no path, return found false.
			return
		}

		fwd_curnode := heap.Pop(fwd_nq).(*node)
		fwd_curnode.open = false
		fwd_curnode.closed = true
		fwd_pather := fwd_curnode.pather
		//fmt.Println(fwd_curnode)

		rev_curnode := heap.Pop(rev_nq).(*node)
		rev_curnode.open = false
		rev_curnode.closed = true
		//rev_pather := rev_curnode.pather
		//fmt.Println(rev_curnode)

		fwd_node_in_rev_map := rev_nodemap.get_node_from_pather(fwd_pather)
		if fwd_node_in_rev_map.closed || fwd_node_in_rev_map.open || fwd_pather == to {
			// Found a path to the goal.
			//fmt.Println("RES:", fwd_node_in_rev_map.closed, fwd_node_in_rev_map.open, fwd_pather) //, rev_pather)

			rp := []Pather{}
			curr := fwd_node_in_rev_map
			for curr != nil {
				rp = append(rp, curr.pather)
				curr = curr.parent
			}

			// reverse the path from touchpoint to "to"
			p := []Pather{}
			for i := len(rp) - 1; i >= 0; i = i - 1 {
				p = append(p, rp[i])
				//fmt.Println(rp[i])
			}
			//fmt.Println("revdone")

			curr = fwd_curnode.parent
			for curr != nil {
				p = append(p, curr.pather)
				//fmt.Println(curr.pather)
				curr = curr.parent
			}

			return p, fwd_curnode.parent.cost + rev_curnode.cost, true
		}

		expand(fwd_nodemap, fwd_nq, fwd_curnode, to)
		expand(rev_nodemap, rev_nq, rev_curnode, from)

	}
}
<|endoftext|>


<commit_before>package cheshire

import(
    "log"
    "sync"
)

// This is a special logger.  It has the same methods as the standard golang Logger class,
// but allows you to register for updates.
// This allows us to expose the logging events easily via an api call.
type Logger struct {
    log.Logger
    inchan chan LoggerEvent
    outchans []chan LoggerEvent
    lock sync.Mutex
    //The event type that will show up when using the log standard calls (default to "log")
    Type string
}

type LoggerEvent struct {
    Type string
    Message string
}

var log = NewLogger()

func Fatal(v ...interface{}) {
    log.Fatal(v)
}
func Fatalf(format string, v ...interface{}) {
    log.Fatal(format, v)
}
func Fatalln(v ...interface{}) {
    log.Fatalln(v)
}
func Flags() int {
    return log.Flags()
}
func Panic(v ...interface{}) {
    log.Panic(v)
}
func Panicf(format string, v ...interface{}) {
    log.Panicf(format, v)
}
func Panicln(v ...interface{}) {
    log.Panicln(v)
}
func Prefix() string {
    return log.Prefix()
}
func Print(v ...interface{}) {
    log.Print(v)
}
func Printf(format string, v ...interface{}) {
    log.Printf(format, v)
}
func Println(v ...interface{}) {
    log.Println(v)
}
func SetFlags(flag int) {
    log.SetFlags(flag)
}
func SetOutput(w io.Writer) {
    log.SetOutput(w)
}
func SetPrefix(prefix string) {
    log.SetPrefix(prefix)
}

func Listen(eventchan chan LoggerEvent) {
    log.Listen(eventchan)
}

func Unlisten(eventchan chan LoggerEvent) {
    log.Unlisten(eventchan)
}
func Emit(eventType, eventMessage string) {
    log.Emit(eventType, eventMessage)
}

// Creates a new Logger object
func NewLogger() *Logger{
    logger := &Logger{
        inchan : make(chan LoggerEvent, 10),
        outchans : make([]chan LoggerEvent, 0),
        Type : "log",
    }

    logger.Logger = *log.New(logger, "", 0)

    go func(logger *Logger) {
        for {
            e := <- logger.inchan
            logger.lock.Lock()
            for _, out := range(logger.outchans) {
                go func(event LoggerEvent) {
                    select {
                        case out <- event:
                        default: //the channel is unavail.
                            // we assume the channel owner will clean up..
                    }
                }(e)
            }
            logger.lock.Unlock()
        }
    }(logger)
    return logger
}

//Conform to Writer interface.  will write events as "log", string
// This allows us to use this in Logger object.
//Will Effectively never throw an error
func (this *Logger) Write(p []byte) (n int, err error) {
    this.Emit("log", string(p))
    //also log to stdout
    log.Println(string(p))
    return len(p), nil
}

// Emits this message to all the listening channels
func (this *Logger) Emit(eventType, eventMessage string) {
    this.inchan <- LoggerEvent{Type: eventType, Message:eventMessage}
}

func (this *Logger) Listen(eventchan chan LoggerEvent) {
    this.lock.Lock()
    defer this.lock.Unlock()
    this.outchans = append(this.outchans, eventchan)
}

func (this *Logger) Unlisten(eventchan chan LoggerEvent) {
    this.lock.Lock()
    defer this.lock.Unlock()
    this.remove(eventchan)
}

func (this *Logger) remove(eventchan chan LoggerEvent) {
    ch := make([]chan LoggerEvent, 0)
    for _, c := range(this.outchans) {
        if c != eventchan {
            ch = append(ch, c)
        } else {
            log.Println("Removing channel from cheshire.Logger...")
        }
    }
    this.outchans = ch
}<commit_msg>fix logger compile bugs<commit_after>package cheshire

import(
    golog "log"
    "sync"
)

// This is a special logger.  It has the same methods as the standard golang Logger class,
// but allows you to register for updates.
// This allows us to expose the logging events easily via an api call.
type Logger struct {
    golog.Logger
    inchan chan LoggerEvent
    outchans []chan LoggerEvent
    lock sync.Mutex
    //The event type that will show up when using the log standard calls (default to "log")
    Type string
}

type LoggerEvent struct {
    Type string
    Message string
}

var log = NewLogger()

func Fatal(v ...interface{}) {
    log.Fatal(v)
}
func Fatalf(format string, v ...interface{}) {
    log.Fatal(format, v)
}
func Fatalln(v ...interface{}) {
    log.Fatalln(v)
}
func Flags() int {
    return log.Flags()
}
func Panic(v ...interface{}) {
    log.Panic(v)
}
func Panicf(format string, v ...interface{}) {
    log.Panicf(format, v)
}
func Panicln(v ...interface{}) {
    log.Panicln(v)
}
func Prefix() string {
    return log.Prefix()
}
func Print(v ...interface{}) {
    log.Print(v)
}
func Printf(format string, v ...interface{}) {
    log.Printf(format, v)
}
func Println(v ...interface{}) {
    log.Println(v)
}
func SetFlags(flag int) {
    log.SetFlags(flag)
}
func SetPrefix(prefix string) {
    log.SetPrefix(prefix)
}

func Listen(eventchan chan LoggerEvent) {
    log.Listen(eventchan)
}

func Unlisten(eventchan chan LoggerEvent) {
    log.Unlisten(eventchan)
}
func Emit(eventType, eventMessage string) {
    log.Emit(eventType, eventMessage)
}

// Creates a new Logger object
func NewLogger() *Logger{
    logger := &Logger{
        inchan : make(chan LoggerEvent, 10),
        outchans : make([]chan LoggerEvent, 0),
        Type : "log",
    }

    logger.Logger = *golog.New(logger, "", 0)

    go func(logger *Logger) {
        for {
            e := <- logger.inchan
            logger.lock.Lock()
            for _, out := range(logger.outchans) {
                go func(event LoggerEvent) {
                    select {
                        case out <- event:
                        default: //the channel is unavail.
                            // we assume the channel owner will clean up..
                    }
                }(e)
            }
            logger.lock.Unlock()
        }
    }(logger)
    return logger
}

//Conform to Writer interface.  will write events as "log", string
// This allows us to use this in Logger object.
//Will Effectively never throw an error
func (this *Logger) Write(p []byte) (n int, err error) {
    this.Emit("log", string(p))
    //also log to stdout
    golog.Println(string(p))
    return len(p), nil
}

// Emits this message to all the listening channels
func (this *Logger) Emit(eventType, eventMessage string) {
    this.inchan <- LoggerEvent{Type: eventType, Message:eventMessage}
}

func (this *Logger) Listen(eventchan chan LoggerEvent) {
    this.lock.Lock()
    defer this.lock.Unlock()
    this.outchans = append(this.outchans, eventchan)
}

func (this *Logger) Unlisten(eventchan chan LoggerEvent) {
    this.lock.Lock()
    defer this.lock.Unlock()
    this.remove(eventchan)
}

func (this *Logger) remove(eventchan chan LoggerEvent) {
    ch := make([]chan LoggerEvent, 0)
    for _, c := range(this.outchans) {
        if c != eventchan {
            ch = append(ch, c)
        } else {
            golog.Println("Removing channel from cheshire.Logger...")
        }
    }
    this.outchans = ch
}<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
)

type configCmd struct {
	httpAddr string
}

func (c *configCmd) usage() string {
	return gettext.Gettext(
		"Manage configuration.\n" +
			"\n" +
			"lxc config set [remote] password <newpwd>        Set admin password\n" +
			"lxc trust list [remote]                          List all trusted certs.\n" +
			"lxc trust add [remote] [certfile.crt]            Add certfile.crt to trusted hosts.\n" +
			"lxc trust remove [remote] [hostname|fingerprint] Remove the cert from trusted hosts.\n")
}

func (c *configCmd) flags() {}

func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "set":
		action := args[1]
		if action == "password" {
			if len(args) != 3 {
				return errArgs
			}

			password := args[2]
			c, err := lxd.NewClient(config, "")
			if err != nil {
				return err
			}

			_, err = c.SetRemotePwd(password)
			return err
		}

		return fmt.Errorf(gettext.Gettext("Only 'password' can be set currently"))
	case "trust":
		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			for host, fingerprint := range trust {
				fmt.Println(fmt.Sprintf("%s: %s", host, fingerprint))
			}

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No cert provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			toRemove := args[len(args)-1]
			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			/* Try to remove by hostname first. */
			for host, fingerprint := range trust {
				if host == toRemove {
					return d.CertificateRemove(fingerprint)
				}
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1])
		}
	default:
		return fmt.Errorf(gettext.Gettext("Unknown config command %s"), args[0])
	}
}
<commit_msg>Fix a few places where we use args without checking for them<commit_after>package main

import (
	"fmt"

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
)

type configCmd struct {
	httpAddr string
}

func (c *configCmd) usage() string {
	return gettext.Gettext(
		"Manage configuration.\n" +
			"\n" +
			"lxc config set [remote] password <newpwd>        Set admin password\n" +
			"lxc trust list [remote]                          List all trusted certs.\n" +
			"lxc trust add [remote] [certfile.crt]            Add certfile.crt to trusted hosts.\n" +
			"lxc trust remove [remote] [hostname|fingerprint] Remove the cert from trusted hosts.\n")
}

func (c *configCmd) flags() {}

func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "set":
		if len(args) < 2 {
			return errArgs
		}

		action := args[1]
		if action == "password" {
			if len(args) != 3 {
				return errArgs
			}

			password := args[2]
			c, err := lxd.NewClient(config, "")
			if err != nil {
				return err
			}

			_, err = c.SetRemotePwd(password)
			return err
		}

		return fmt.Errorf(gettext.Gettext("Only 'password' can be set currently"))
	case "trust":
		if len(args) < 2 {
			return errArgs
		}

		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			for host, fingerprint := range trust {
				fmt.Println(fmt.Sprintf("%s: %s", host, fingerprint))
			}

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No cert provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			toRemove := args[len(args)-1]
			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			/* Try to remove by hostname first. */
			for host, fingerprint := range trust {
				if host == toRemove {
					return d.CertificateRemove(fingerprint)
				}
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1])
		}
	default:
		return fmt.Errorf(gettext.Gettext("Unknown config command %s"), args[0])
	}
}
<|endoftext|>