<commit_before>// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This binary provides sample code for using the gopacket TCP assembler and TCP
// stream reader.  It reads packets off the wire and reconstructs HTTP requests
// it sees, logging them.
package main

import (
	"bufio"
	"flag"
	"io"
	"log"
	"net/http"
	"time"
	"fmt"

	"github.com/google/gopacket"
	"github.com/google/gopacket/examples/util"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/google/gopacket/tcpassembly"
	"github.com/google/gopacket/tcpassembly/tcpreader"
)

var iface = flag.String("i", "en0", "Interface to get packets from")
var fname = flag.String("r", "", "Filename to read from, overrides -i")
var snaplen = flag.Int("s", 1600, "SnapLen for pcap packet capture")
var filter = flag.String("f", "tcp and port 80", "BPF filter for pcap")
var logAllPackets = flag.Bool("v", false, "Logs every packet in great detail")

// Build a simple HTTP request parser using tcpassembly.StreamFactory and tcpassembly.Stream interfaces

// httpStreamFactory implements tcpassembly.StreamFactory
type httpStreamFactory struct{}

// httpStream will handle the actual decoding of http requests.
type httpStream struct {
	net, transport gopacket.Flow
	r              tcpreader.ReaderStream
}

func (h *httpStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
	hstream := &httpStream{
		net:       net,
		transport: transport,
		r:         tcpreader.NewReaderStream(),
	}

	src,_ := transport.Endpoints()
	if fmt.Sprintf("%v",src) == "80" {
		go hstream.runResponse() // Important... we must guarantee that data from the reader stream is read.
	} else {
		go hstream.runRequest() // Important... we must guarantee that data from the reader stream is read.
	}

	// ReaderStream implements tcpassembly.Stream, so we can return a pointer to it.
	return &hstream.r
}

func (h *httpStream) runResponse() {

	buf := bufio.NewReader(&h.r)
	defer tcpreader.DiscardBytesToEOF(buf)
	for {
		resp, err := http.ReadResponse(buf,nil)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			// We must read until we see an EOF... very important!
			return
		} else if err != nil {
			log.Println("Error reading stream", h.net, h.transport, ":", err)
			return
		} else {
			bodyBytes := tcpreader.DiscardBytesToEOF(resp.Body)
			resp.Body.Close()
			log.Println("Received response from stream", h.net, h.transport, ":", resp, "with", bodyBytes, "bytes in response body")
		}
	}
}
func (h *httpStream) runRequest() {

	buf := bufio.NewReader(&h.r)
	defer tcpreader.DiscardBytesToEOF(buf)
	for {
		req, err := http.ReadRequest(buf)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			// We must read until we see an EOF... very important!
			return
		} else if err != nil {
			log.Println("Error reading stream", h.net, h.transport, ":", err)
		} else {
			bodyBytes := tcpreader.DiscardBytesToEOF(req.Body)
			req.Body.Close()
			log.Println("Received request from stream", h.net, h.transport, ":", req, "with", bodyBytes, "bytes in request body")
		}
	}
}

func main() {
	defer util.Run()()
	var handle *pcap.Handle
	var err error

	// Set up pcap packet capture
	if *fname != "" {
		log.Printf("Reading from pcap dump %q", *fname)
		handle, err = pcap.OpenOffline(*fname)
	} else {
		log.Printf("Starting capture on interface %q", *iface)
		handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever)
	}
	if err != nil {
		log.Fatal(err)
	}

	if err := handle.SetBPFFilter(*filter); err != nil {
		log.Fatal(err)
	}

	// Set up assembly
	streamFactory := &httpStreamFactory{}
	streamPool := tcpassembly.NewStreamPool(streamFactory)
	assembler := tcpassembly.NewAssembler(streamPool)

	log.Println("reading in packets")
	// Read in packets, pass to assembler.
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	packets := packetSource.Packets()
	ticker := time.Tick(time.Minute)
	for {
		select {
		case packet := <-packets:
			// A nil packet indicates the end of a pcap file.
			if packet == nil {
				return
			}
			if *logAllPackets {
				log.Println(packet)
			}
			if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP {
				log.Println("Unusable packet")
				continue
			}
			tcp := packet.TransportLayer().(*layers.TCP)
			assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
		case <-ticker:
			// Every minute, flush connections that haven't seen activity in the past 2 minutes.
			assembler.FlushOlderThan(time.Now().Add(time.Minute * -2))
		}
	}
}
<commit_msg>add print request and response<commit_after>// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This binary provides sample code for using the gopacket TCP assembler and TCP
// stream reader.  It reads packets off the wire and reconstructs HTTP requests
// it sees, logging them.
package main

import (
	"bufio"
	"flag"
	"io"
	"log"
	"net/http"
	"time"
	"fmt"

	"github.com/google/gopacket"
	"github.com/google/gopacket/examples/util"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/google/gopacket/tcpassembly"
	"github.com/google/gopacket/tcpassembly/tcpreader"
)

var iface = flag.String("i", "en0", "Interface to get packets from")
var fname = flag.String("r", "", "Filename to read from, overrides -i")
var snaplen = flag.Int("s", 1600, "SnapLen for pcap packet capture")
var filter = flag.String("f", "tcp and port 80", "BPF filter for pcap")
var logAllPackets = flag.Bool("v", false, "Logs every packet in great detail")

// Build a simple HTTP request parser using tcpassembly.StreamFactory and tcpassembly.Stream interfaces

// httpStreamFactory implements tcpassembly.StreamFactory
type httpStreamFactory struct{}

// httpStream will handle the actual decoding of http requests.
type httpStream struct {
	net, transport gopacket.Flow
	r              tcpreader.ReaderStream
}

func (h *httpStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
	hstream := &httpStream{
		net:       net,
		transport: transport,
		r:         tcpreader.NewReaderStream(),
	}

	src,_ := transport.Endpoints()
	if fmt.Sprintf("%v",src) == "80" {
		go hstream.runResponse() // Important... we must guarantee that data from the reader stream is read.
	} else {
		go hstream.runRequest() // Important... we must guarantee that data from the reader stream is read.
	}

	// ReaderStream implements tcpassembly.Stream, so we can return a pointer to it.
	return &hstream.r
}

func (h *httpStream) runResponse() {

	buf := bufio.NewReader(&h.r)
	defer tcpreader.DiscardBytesToEOF(buf)
	for {
		resp, err := http.ReadResponse(buf,nil)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			// We must read until we see an EOF... very important!
			return
		} else if err != nil {
			log.Println("Error reading stream", h.net, h.transport, ":", err)
			return
		} else {
			bodyBytes := tcpreader.DiscardBytesToEOF(resp.Body)
			resp.Body.Close()
			printResponse(resp,h,bodyBytes)
			// log.Println("Received response from stream", h.net, h.transport, ":", resp, "with", bodyBytes, "bytes in response body")
		}
	}
}
func (h *httpStream) runRequest() {

	buf := bufio.NewReader(&h.r)
	defer tcpreader.DiscardBytesToEOF(buf)
	for {
		req, err := http.ReadRequest(buf)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			// We must read until we see an EOF... very important!
			return
		} else if err != nil {
			log.Println("Error reading stream", h.net, h.transport, ":", err)
		} else {
			bodyBytes := tcpreader.DiscardBytesToEOF(req.Body)
			req.Body.Close()
			printRequest(req,h,bodyBytes)
			// log.Println("Received request from stream", h.net, h.transport, ":", req, "with", bodyBytes, "bytes in request body")
		}
	}
}

func printHeader(h http.Header){
	for k,v := range h{
		fmt.Println(k,v)
	}
}

func printRequest(req *http.Request,h *httpStream,bodyBytes int){

	fmt.Println("\n\r\n\r")
	fmt.Println(h.net,h.transport)
	fmt.Println("\n\r")
	fmt.Println(req.Method, req.RequestURI, req.Proto)
	printHeader(req.Header)

}

func printResponse(resp *http.Response,h *httpStream,bodyBytes int){

	fmt.Println("\n\r")
	fmt.Println(resp.Proto, resp.Status)
	printHeader(resp.Header)
}

func main() {
	defer util.Run()()
	var handle *pcap.Handle
	var err error

	// Set up pcap packet capture
	if *fname != "" {
		log.Printf("Reading from pcap dump %q", *fname)
		handle, err = pcap.OpenOffline(*fname)
	} else {
		log.Printf("Starting capture on interface %q", *iface)
		handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever)
	}
	if err != nil {
		log.Fatal(err)
	}

	if err := handle.SetBPFFilter(*filter); err != nil {
		log.Fatal(err)
	}

	// Set up assembly
	streamFactory := &httpStreamFactory{}
	streamPool := tcpassembly.NewStreamPool(streamFactory)
	assembler := tcpassembly.NewAssembler(streamPool)

	log.Println("reading in packets")
	// Read in packets, pass to assembler.
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	packets := packetSource.Packets()
	ticker := time.Tick(time.Minute)
	for {
		select {
		case packet := <-packets:
			// A nil packet indicates the end of a pcap file.
			if packet == nil {
				return
			}
			if *logAllPackets {
				log.Println(packet)
			}
			if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP {
				log.Println("Unusable packet")
				continue
			}
			tcp := packet.TransportLayer().(*layers.TCP)
			assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
		case <-ticker:
			// Every minute, flush connections that haven't seen activity in the past 2 minutes.
			assembler.FlushOlderThan(time.Now().Add(time.Minute * -2))
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Minimalist Object Storage, (C) 2015 Minio, Inc.
 *
 * 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 logging

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
	"time"

	"github.com/minio/minio/pkg/iodine"
	"github.com/minio/minio/pkg/utils/log"
)

type logHandler struct {
	http.Handler
	Logger chan<- string
}

// LogMessage is a serializable json log message
type LogMessage struct {
	Request         *http.Request
	StartTime       time.Time
	Duration        time.Duration
	Status          int
	StatusText      string
	ResponseHeaders http.Header
}

// LogWriter is used to capture status for log messages
type LogWriter struct {
	ResponseWriter http.ResponseWriter
	LogMessage     *LogMessage
}

// WriteHeader writes headers and stores status in LogMessage
func (w *LogWriter) WriteHeader(status int) {
	w.LogMessage.StatusText = http.StatusText(status)
	w.LogMessage.Status = status
	w.ResponseWriter.WriteHeader(status)
}

// Header Dummy wrapper for LogWriter
func (w *LogWriter) Header() http.Header {
	return w.ResponseWriter.Header()
}

// Write Dummy wrapper for LogWriter
func (w *LogWriter) Write(data []byte) (int, error) {
	return w.ResponseWriter.Write(data)
}

func (h *logHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logMessage := &LogMessage{
		StartTime: time.Now().UTC(),
	}
	logWriter := &LogWriter{ResponseWriter: w, LogMessage: logMessage}
	h.Handler.ServeHTTP(logWriter, req)
	logMessage.ResponseHeaders = w.Header()
	logMessage.Request = req
	logMessage.Duration = time.Now().UTC().Sub(logMessage.StartTime)
	js, _ := json.Marshal(logMessage)
	h.Logger <- string(js)
}

// LogHandler logs requests
func LogHandler(h http.Handler) http.Handler {
	logger, _ := FileLogger("access.log")
	return &logHandler{Handler: h, Logger: logger}
}

// FileLogger returns a channel that is used to write to the logger
func FileLogger(filename string) (chan<- string, error) {
	ch := make(chan string)
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		return nil, iodine.New(err, map[string]string{"logfile": filename})
	}
	go func() {
		for message := range ch {
			if _, err := io.Copy(file, bytes.NewBufferString(message+"\n")); err != nil {
				log.Println(iodine.New(err, nil))
			}
		}
	}()
	return ch, nil
}
<commit_msg>Enhance logging handler to print in humanize form for ContentLength<commit_after>/*
 * Minimalist Object Storage, (C) 2015 Minio, Inc.
 *
 * 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 logging

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/minio/minio/pkg/iodine"
	"github.com/minio/minio/pkg/utils/log"
)

type logHandler struct {
	http.Handler
	Logger chan<- []byte
}

// LogMessage is a serializable json log message
type LogMessage struct {
	StartTime     time.Time
	Duration      time.Duration
	StatusMessage string // human readable http status message
	ContentLength string // human readable content length

	// HTTP detailed message
	HTTP struct {
		ResponseHeaders http.Header
		Request         *http.Request
	}
}

// LogWriter is used to capture status for log messages
type LogWriter struct {
	ResponseWriter http.ResponseWriter
	LogMessage     *LogMessage
}

// WriteHeader writes headers and stores status in LogMessage
func (w *LogWriter) WriteHeader(status int) {
	w.LogMessage.StatusMessage = http.StatusText(status)
	w.ResponseWriter.WriteHeader(status)
}

// Header Dummy wrapper for LogWriter
func (w *LogWriter) Header() http.Header {
	return w.ResponseWriter.Header()
}

// Write Dummy wrapper for LogWriter
func (w *LogWriter) Write(data []byte) (int, error) {
	return w.ResponseWriter.Write(data)
}

func (h *logHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logMessage := &LogMessage{
		StartTime: time.Now().UTC(),
	}
	logWriter := &LogWriter{ResponseWriter: w, LogMessage: logMessage}
	h.Handler.ServeHTTP(logWriter, req)
	h.Logger <- getLogMessage(logMessage, w, req)
}

func getLogMessage(logMessage *LogMessage, w http.ResponseWriter, req *http.Request) []byte {
	// store lower level details
	logMessage.HTTP.ResponseHeaders = w.Header()
	logMessage.HTTP.Request = req

	// humanize content-length to be printed in logs
	contentLength, _ := strconv.Atoi(logMessage.HTTP.ResponseHeaders.Get("Content-Length"))
	logMessage.ContentLength = humanize.IBytes(uint64(contentLength))
	logMessage.Duration = time.Now().UTC().Sub(logMessage.StartTime)
	js, _ := json.Marshal(logMessage)
	js = append(js, byte('\n')) // append a new line
	return js
}

// LogHandler logs requests
func LogHandler(h http.Handler) http.Handler {
	logger, _ := FileLogger("access.log")
	return &logHandler{Handler: h, Logger: logger}
}

// FileLogger returns a channel that is used to write to the logger
func FileLogger(filename string) (chan<- []byte, error) {
	ch := make(chan []byte)
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		return nil, iodine.New(err, map[string]string{"logfile": filename})
	}
	go func() {
		for message := range ch {
			if _, err := io.Copy(file, bytes.NewBuffer(message)); err != nil {
				log.Println(iodine.New(err, nil))
			}
		}
	}()
	return ch, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 batch

import (
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
)

// GroupName is the group name use in this package
const GroupName = "batch"

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}

// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) unversioned.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) unversioned.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&Job{},
		&JobList{},
		&JobTemplate{},
		&CronJob{},
		&CronJobList{},
		&api.ListOptions{},
	)
	scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJob"), &CronJob{})
	scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJobList"), &CronJobList{})
	return nil
}
<commit_msg>Register api.DeleteOptions for internal batch group<commit_after>/*
Copyright 2016 The Kubernetes 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 batch

import (
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
)

// GroupName is the group name use in this package
const GroupName = "batch"

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}

// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) unversioned.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) unversioned.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&Job{},
		&JobList{},
		&JobTemplate{},
		&CronJob{},
		&CronJobList{},
		&api.ListOptions{},
		&api.DeleteOptions{},
	)
	scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJob"), &CronJob{})
	scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJobList"), &CronJobList{})
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"errors"
	"fmt"
	"io"

	kapi "k8s.io/kubernetes/pkg/api"
	kapierrors "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/client/restclient"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
	kubecmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

	"github.com/openshift/origin/pkg/client"
	cliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/project/api"

	"github.com/spf13/cobra"
)

type ProjectOptions struct {
	Config       clientcmdapi.Config
	ClientConfig *restclient.Config
	ClientFn     func() (*client.Client, error)
	Out          io.Writer
	PathOptions  *kubecmdconfig.PathOptions

	ProjectName  string
	ProjectOnly  bool
	DisplayShort bool

	// SkipAccessValidation means that if a specific name is requested, don't bother checking for access to the project
	SkipAccessValidation bool
}

const (
	projectLong = `
Switch to another project and make it the default in your configuration

If no project was specified on the command line, display information about the current active
project. Since you can use this command to connect to projects on different servers, you will
occasionally encounter projects of the same name on different servers. When switching to that
project, a new local context will be created that will have a unique name - for instance,
'myapp-2'. If you have previously created a context with a different name than the project
name, this command will accept that context name instead.

For advanced configuration, or to manage the contents of your config file, use the 'config'
command.`

	projectExample = `  # Switch to 'myapp' project
  %[1]s myapp

  # Display the project currently in use
  %[1]s`
)

// NewCmdProject implements the OpenShift cli rollback command
func NewCmdProject(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
	options := &ProjectOptions{}

	cmd := &cobra.Command{
		Use:     "project [NAME]",
		Short:   "Switch to another project",
		Long:    projectLong,
		Example: fmt.Sprintf(projectExample, fullName),
		Aliases: []string{"projects"},
		Run: func(cmd *cobra.Command, args []string) {
			options.PathOptions = cliconfig.NewPathOptions(cmd)

			if err := options.Complete(f, args, out); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if err := options.RunProject(); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}
	cmd.Flags().BoolVarP(&options.DisplayShort, "short", "q", false, "If true, display only the project name")
	return cmd
}

func (o *ProjectOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error {
	var err error

	argsLength := len(args)
	switch {
	case argsLength > 1:
		return errors.New("Only one argument is supported (project name or context name).")
	case argsLength == 1:
		o.ProjectName = args[0]
	}

	o.Config, err = f.OpenShiftClientConfig.RawConfig()
	if err != nil {
		return err
	}

	o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig()
	if err != nil {
		return err
	}

	o.ClientFn = func() (*client.Client, error) {
		client, _, err := f.Clients()
		return client, err
	}

	o.Out = out

	return nil
}
func (o ProjectOptions) Validate() error {
	return nil
}

// RunProject contains all the necessary functionality for the OpenShift cli project command
func (o ProjectOptions) RunProject() error {
	config := o.Config
	clientCfg := o.ClientConfig
	out := o.Out

	// No argument provided, we will just print info
	if len(o.ProjectName) == 0 {
		currentContext := config.Contexts[config.CurrentContext]
		currentProject := currentContext.Namespace

		if len(currentProject) > 0 {
			if o.DisplayShort {
				fmt.Fprintln(out, currentProject)
				return nil
			}

			client, err := o.ClientFn()
			if err != nil {
				return err
			}

			if _, err := client.Projects().Get(currentProject); err != nil {
				if kapierrors.IsNotFound(err) {
					return fmt.Errorf("the project %q specified in your config does not exist.", currentProject)
				}
				if clientcmd.IsForbidden(err) {
					return fmt.Errorf("you do not have rights to view project %q.", currentProject)
				}
				return err
			}

			defaultContextName := cliconfig.GetContextNickname(currentContext.Namespace, currentContext.Cluster, currentContext.AuthInfo)

			// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
			// a context name they didn't choose
			if config.CurrentContext == defaultContextName {
				fmt.Fprintf(out, "Using project %q on server %q.\n", currentProject, clientCfg.Host)

			} else {
				fmt.Fprintf(out, "Using project %q from context named %q on server %q.\n", currentProject, config.CurrentContext, clientCfg.Host)
			}

		} else {
			if o.DisplayShort {
				return fmt.Errorf("no project has been set")
			}
			fmt.Fprintf(out, "No project has been set. Pass a project name to make that the default.\n")
		}
		return nil
	}

	// We have an argument that can be either a context or project
	argument := o.ProjectName

	contextInUse := ""
	namespaceInUse := ""

	// Check if argument is an existing context, if so just set it as the context in use.
	// If not a context then we will try to handle it as a project.
	if context, contextExists := config.Contexts[argument]; !o.ProjectOnly && contextExists {
		contextInUse = argument
		namespaceInUse = context.Namespace

		config.CurrentContext = argument

	} else {
		if !o.SkipAccessValidation {
			client, err := o.ClientFn()
			if err != nil {
				return err
			}

			if _, err := client.Projects().Get(argument); err != nil {
				if isNotFound, isForbidden := kapierrors.IsNotFound(err), clientcmd.IsForbidden(err); isNotFound || isForbidden {
					var msg string
					if isForbidden {
						msg = fmt.Sprintf("You are not a member of project %q.", argument)
					} else {
						msg = fmt.Sprintf("A project named %q does not exist on %q.", argument, clientCfg.Host)
					}

					projects, err := getProjects(client)
					if err == nil {
						switch len(projects) {
						case 0:
							msg += "\nYou are not a member of any projects. You can request a project to be created with the 'new-project' command."
						case 1:
							msg += fmt.Sprintf("\nYou have one project on this server: %s", api.DisplayNameAndNameForProject(&projects[0]))
						default:
							msg += "\nYour projects are:"
							for _, project := range projects {
								msg += fmt.Sprintf("\n* %s", api.DisplayNameAndNameForProject(&project))
							}
						}
					}

					if hasMultipleServers(config) {
						msg += "\nTo see projects on another server, pass '--server=<server>'."
					}
					return errors.New(msg)
				}
				return err
			}
		}
		projectName := argument

		kubeconfig, err := cliconfig.CreateConfig(projectName, o.ClientConfig)
		if err != nil {
			return err
		}

		merged, err := cliconfig.MergeConfig(config, *kubeconfig)
		if err != nil {
			return err
		}
		config = *merged

		namespaceInUse = projectName
		contextInUse = merged.CurrentContext
	}

	if err := kubecmdconfig.ModifyConfig(o.PathOptions, config, true); err != nil {
		return err
	}

	if o.DisplayShort {
		fmt.Fprintln(out, namespaceInUse)
		return nil
	}

	// calculate what name we'd generate for the context.  If the context has the same name, don't drop it into the output, because the user won't
	// recognize the name since they didn't choose it.
	defaultContextName := cliconfig.GetContextNickname(namespaceInUse, config.Contexts[contextInUse].Cluster, config.Contexts[contextInUse].AuthInfo)

	switch {
	// if there is no namespace, then the only information we can provide is the context and server
	case (len(namespaceInUse) == 0):
		fmt.Fprintf(out, "Now using context named %q on server %q.\n", contextInUse, clientCfg.Host)

	// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
	// a context name they didn't choose
	case (argument == namespaceInUse) && (contextInUse == defaultContextName):
		fmt.Fprintf(out, "Now using project %q on server %q.\n", namespaceInUse, clientCfg.Host)

	// in all other cases, display all information
	default:
		fmt.Fprintf(out, "Now using project %q from context named %q on server %q.\n", namespaceInUse, contextInUse, clientCfg.Host)

	}

	return nil
}

func getProjects(oClient *client.Client) ([]api.Project, error) {
	projects, err := oClient.Projects().List(kapi.ListOptions{})
	if err != nil {
		return nil, err
	}
	return projects.Items, nil
}

func clusterAndAuthEquality(clientCfg *restclient.Config, cluster clientcmdapi.Cluster, authInfo clientcmdapi.AuthInfo) bool {
	return cluster.Server == clientCfg.Host &&
		cluster.InsecureSkipTLSVerify == clientCfg.Insecure &&
		cluster.CertificateAuthority == clientCfg.CAFile &&
		bytes.Equal(cluster.CertificateAuthorityData, clientCfg.CAData) &&
		authInfo.Token == clientCfg.BearerToken &&
		authInfo.ClientCertificate == clientCfg.TLSClientConfig.CertFile &&
		bytes.Equal(authInfo.ClientCertificateData, clientCfg.TLSClientConfig.CertData) &&
		authInfo.ClientKey == clientCfg.TLSClientConfig.KeyFile &&
		bytes.Equal(authInfo.ClientKeyData, clientCfg.TLSClientConfig.KeyData)
}

// TODO these kind of funcs could be moved to some kind of clientcmd util
func hasMultipleServers(config clientcmdapi.Config) bool {
	server := ""
	for _, cluster := range config.Clusters {
		if len(server) == 0 {
			server = cluster.Server
		}
		if server != cluster.Server {
			return true
		}
	}
	return false
}
<commit_msg>oc: inform about switch to the same project<commit_after>package cmd

import (
	"bytes"
	"errors"
	"fmt"
	"io"

	kapi "k8s.io/kubernetes/pkg/api"
	kapierrors "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/client/restclient"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
	kubecmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

	"github.com/openshift/origin/pkg/client"
	cliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/project/api"

	"github.com/spf13/cobra"
)

type ProjectOptions struct {
	Config       clientcmdapi.Config
	ClientConfig *restclient.Config
	ClientFn     func() (*client.Client, error)
	Out          io.Writer
	PathOptions  *kubecmdconfig.PathOptions

	ProjectName  string
	ProjectOnly  bool
	DisplayShort bool

	// SkipAccessValidation means that if a specific name is requested, don't bother checking for access to the project
	SkipAccessValidation bool
}

const (
	projectLong = `
Switch to another project and make it the default in your configuration

If no project was specified on the command line, display information about the current active
project. Since you can use this command to connect to projects on different servers, you will
occasionally encounter projects of the same name on different servers. When switching to that
project, a new local context will be created that will have a unique name - for instance,
'myapp-2'. If you have previously created a context with a different name than the project
name, this command will accept that context name instead.

For advanced configuration, or to manage the contents of your config file, use the 'config'
command.`

	projectExample = `  # Switch to 'myapp' project
  %[1]s myapp

  # Display the project currently in use
  %[1]s`
)

// NewCmdProject implements the OpenShift cli rollback command
func NewCmdProject(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
	options := &ProjectOptions{}

	cmd := &cobra.Command{
		Use:     "project [NAME]",
		Short:   "Switch to another project",
		Long:    projectLong,
		Example: fmt.Sprintf(projectExample, fullName),
		Aliases: []string{"projects"},
		Run: func(cmd *cobra.Command, args []string) {
			options.PathOptions = cliconfig.NewPathOptions(cmd)

			if err := options.Complete(f, args, out); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if err := options.RunProject(); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}
	cmd.Flags().BoolVarP(&options.DisplayShort, "short", "q", false, "If true, display only the project name")
	return cmd
}

func (o *ProjectOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error {
	var err error

	argsLength := len(args)
	switch {
	case argsLength > 1:
		return errors.New("Only one argument is supported (project name or context name).")
	case argsLength == 1:
		o.ProjectName = args[0]
	}

	o.Config, err = f.OpenShiftClientConfig.RawConfig()
	if err != nil {
		return err
	}

	o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig()
	if err != nil {
		return err
	}

	o.ClientFn = func() (*client.Client, error) {
		client, _, err := f.Clients()
		return client, err
	}

	o.Out = out

	return nil
}
func (o ProjectOptions) Validate() error {
	return nil
}

// RunProject contains all the necessary functionality for the OpenShift cli project command
func (o ProjectOptions) RunProject() error {
	config := o.Config
	clientCfg := o.ClientConfig
	out := o.Out

	currentContext := config.Contexts[config.CurrentContext]
	currentProject := currentContext.Namespace

	// No argument provided, we will just print info
	if len(o.ProjectName) == 0 {
		if len(currentProject) > 0 {
			if o.DisplayShort {
				fmt.Fprintln(out, currentProject)
				return nil
			}

			client, err := o.ClientFn()
			if err != nil {
				return err
			}

			if _, err := client.Projects().Get(currentProject); err != nil {
				if kapierrors.IsNotFound(err) {
					return fmt.Errorf("the project %q specified in your config does not exist.", currentProject)
				}
				if clientcmd.IsForbidden(err) {
					return fmt.Errorf("you do not have rights to view project %q.", currentProject)
				}
				return err
			}

			defaultContextName := cliconfig.GetContextNickname(currentContext.Namespace, currentContext.Cluster, currentContext.AuthInfo)

			// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
			// a context name they didn't choose
			if config.CurrentContext == defaultContextName {
				fmt.Fprintf(out, "Using project %q on server %q.\n", currentProject, clientCfg.Host)

			} else {
				fmt.Fprintf(out, "Using project %q from context named %q on server %q.\n", currentProject, config.CurrentContext, clientCfg.Host)
			}

		} else {
			if o.DisplayShort {
				return fmt.Errorf("no project has been set")
			}
			fmt.Fprintf(out, "No project has been set. Pass a project name to make that the default.\n")
		}
		return nil
	}

	// We have an argument that can be either a context or project
	argument := o.ProjectName

	contextInUse := ""
	namespaceInUse := ""

	// Check if argument is an existing context, if so just set it as the context in use.
	// If not a context then we will try to handle it as a project.
	if context, contextExists := config.Contexts[argument]; !o.ProjectOnly && contextExists {
		contextInUse = argument
		namespaceInUse = context.Namespace

		config.CurrentContext = argument

	} else {
		if !o.SkipAccessValidation {
			client, err := o.ClientFn()
			if err != nil {
				return err
			}

			if _, err := client.Projects().Get(argument); err != nil {
				if isNotFound, isForbidden := kapierrors.IsNotFound(err), clientcmd.IsForbidden(err); isNotFound || isForbidden {
					var msg string
					if isForbidden {
						msg = fmt.Sprintf("You are not a member of project %q.", argument)
					} else {
						msg = fmt.Sprintf("A project named %q does not exist on %q.", argument, clientCfg.Host)
					}

					projects, err := getProjects(client)
					if err == nil {
						switch len(projects) {
						case 0:
							msg += "\nYou are not a member of any projects. You can request a project to be created with the 'new-project' command."
						case 1:
							msg += fmt.Sprintf("\nYou have one project on this server: %s", api.DisplayNameAndNameForProject(&projects[0]))
						default:
							msg += "\nYour projects are:"
							for _, project := range projects {
								msg += fmt.Sprintf("\n* %s", api.DisplayNameAndNameForProject(&project))
							}
						}
					}

					if hasMultipleServers(config) {
						msg += "\nTo see projects on another server, pass '--server=<server>'."
					}
					return errors.New(msg)
				}
				return err
			}
		}
		projectName := argument

		kubeconfig, err := cliconfig.CreateConfig(projectName, o.ClientConfig)
		if err != nil {
			return err
		}

		merged, err := cliconfig.MergeConfig(config, *kubeconfig)
		if err != nil {
			return err
		}
		config = *merged

		namespaceInUse = projectName
		contextInUse = merged.CurrentContext
	}

	if err := kubecmdconfig.ModifyConfig(o.PathOptions, config, true); err != nil {
		return err
	}

	if o.DisplayShort {
		fmt.Fprintln(out, namespaceInUse)
		return nil
	}

	// calculate what name we'd generate for the context.  If the context has the same name, don't drop it into the output, because the user won't
	// recognize the name since they didn't choose it.
	defaultContextName := cliconfig.GetContextNickname(namespaceInUse, config.Contexts[contextInUse].Cluster, config.Contexts[contextInUse].AuthInfo)

	switch {
	// if there is no namespace, then the only information we can provide is the context and server
	case (len(namespaceInUse) == 0):
		fmt.Fprintf(out, "Now using context named %q on server %q.\n", contextInUse, clientCfg.Host)

	// inform them that they are already in the project they are trying to switch to
	case currentProject == namespaceInUse:
		fmt.Fprintf(out, "Already on project %q on server %q.\n", currentProject, clientCfg.Host)

	// if they specified a project name and got a generated context, then only show the information they care about.  They won't recognize
	// a context name they didn't choose
	case (argument == namespaceInUse) && (contextInUse == defaultContextName):
		fmt.Fprintf(out, "Now using project %q on server %q.\n", namespaceInUse, clientCfg.Host)

	// in all other cases, display all information
	default:
		fmt.Fprintf(out, "Now using project %q from context named %q on server %q.\n", namespaceInUse, contextInUse, clientCfg.Host)

	}

	return nil
}

func getProjects(oClient *client.Client) ([]api.Project, error) {
	projects, err := oClient.Projects().List(kapi.ListOptions{})
	if err != nil {
		return nil, err
	}
	return projects.Items, nil
}

func clusterAndAuthEquality(clientCfg *restclient.Config, cluster clientcmdapi.Cluster, authInfo clientcmdapi.AuthInfo) bool {
	return cluster.Server == clientCfg.Host &&
		cluster.InsecureSkipTLSVerify == clientCfg.Insecure &&
		cluster.CertificateAuthority == clientCfg.CAFile &&
		bytes.Equal(cluster.CertificateAuthorityData, clientCfg.CAData) &&
		authInfo.Token == clientCfg.BearerToken &&
		authInfo.ClientCertificate == clientCfg.TLSClientConfig.CertFile &&
		bytes.Equal(authInfo.ClientCertificateData, clientCfg.TLSClientConfig.CertData) &&
		authInfo.ClientKey == clientCfg.TLSClientConfig.KeyFile &&
		bytes.Equal(authInfo.ClientKeyData, clientCfg.TLSClientConfig.KeyData)
}

// TODO these kind of funcs could be moved to some kind of clientcmd util
func hasMultipleServers(config clientcmdapi.Config) bool {
	server := ""
	for _, cluster := range config.Clusters {
		if len(server) == 0 {
			server = cluster.Server
		}
		if server != cluster.Server {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package docstore

import (
	"testing"

	"a4.io/blobstash/pkg/docstore/id"
)

func TestIndexBasic(t *testing.T) {
	i, err := newSortIndex("name", "name")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()
	_id, _ := id.New(3)
	v := buildVal(1, _id)
	t.Logf("v=%+v\n", v)
	s, _id2 := parseVal(v)
	if s != 1 {
		t.Errorf("failed to parse start, got %q, expected 1", s)
	}
	if _id2.String() != _id.String() {
		t.Errorf("failed to parse ID, got %v, expected %v", _id2.String(), _id.String())
	}
}

func TestBuildIndexKey(t *testing.T) {
	k := buildKey("lol")
	t.Logf("k=%+v\n", k)
}

func TestIndex(t *testing.T) {
	i, err := newSortIndex("letter", "letter")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()

	_id1, _ := id.New(1)
	_id1.SetVersion(1)
	if err := i.Index(_id1, map[string]interface{}{"letter": "adeeee"}); err != nil {
		panic(err)
	}

	_id2, _ := id.New(2)
	_id2.SetVersion(2)
	if err := i.Index(_id2, map[string]interface{}{"letter": "aa"}); err != nil {
		panic(err)
	}

	_ids, cursor, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids=%q\ncursor=%v\n", _ids, cursor)

	if len(_ids) != 2 {
		t.Errorf("expected 2 _ids at first iter, got %d", len(_ids))
	}
	if _ids[0].String() != _id1.String() || _ids[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fist iter to be _id1")
	}
	if _ids[1].String() != _id2.String() || _ids[1].Version() != _id2.Version() {
		t.Errorf("expected second id for fist iter to be _id2")
	}

	_id21, _ := id.FromHex(_id2.String())
	_id21.SetVersion(3)
	if err := i.Index(_id21, map[string]interface{}{"letter": "z"}); err != nil {
		panic(err)
	}

	_ids2, cursor2, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids2=%q\ncursor2=%v\n", _ids2, cursor2)
	if len(_ids2) != 2 {
		t.Errorf("expected 2 _ids2 at second iter, got %d", len(_ids2))
	}
	if _ids2[0].String() != _id21.String() || _ids2[0].Version() != _id21.Version() {
		t.Errorf("expected first id for second iter to be _id21")
	}
	if _ids2[1].String() != _id1.String() || _ids2[1].Version() != _id1.Version() {
		t.Errorf("expected second id for second iter to be _id1")
	}

	_ids3, cursor3, err := i.Iter("lol", "", 50, 2)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids3=%q\ncursor3=%v\n", _ids3, cursor3)

	if len(_ids3) != 2 {
		t.Errorf("expected 2 _ids at third iter, got %d", len(_ids3))
	}
	if _ids3[0].String() != _id1.String() || _ids3[0].Version() != _id1.Version() {
		t.Errorf("expected first id for third iter to be _id1")
	}
	if _ids3[1].String() != _id2.String() || _ids3[1].Version() != _id2.Version() {
		t.Errorf("expected second id for third iter to be _id2")
	}

	_id2.SetVersion(4)
	_id2.SetFlag(flagDeleted)

	if err := i.Index(_id2, nil); err != nil {
		panic(err)
	}

	_ids4, cursor4, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids4=%q\ncursor4=%v\n", _ids4, cursor4)

	if len(_ids4) != 1 {
		t.Errorf("expected 1 _ids at fourth iter, got %d", len(_ids3))
	}
	if _ids4[0].String() != _id1.String() || _ids4[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fourth iter to be _id1")
	}
}

func TestIndexUpdatedField(t *testing.T) {
	i, err := newSortIndex("letter", "_updated")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()

	_id1, _ := id.New(2)
	_id1.SetVersion(2)
	if err := i.Index(_id1, map[string]interface{}{"letter": "adeeee"}); err != nil {
		panic(err)
	}

	_id2, _ := id.New(1)
	_id2.SetVersion(1)
	if err := i.Index(_id2, map[string]interface{}{"letter": "aa"}); err != nil {
		panic(err)
	}

	_ids, cursor, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids=%q\ncursor=%v\n", _ids, cursor)

	if len(_ids) != 2 {
		t.Errorf("expected 2 _ids at first iter, got %d", len(_ids))
	}
	if _ids[0].String() != _id1.String() || _ids[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fist iter to be _id1")
	}
	if _ids[1].String() != _id2.String() || _ids[1].Version() != _id2.Version() {
		t.Errorf("expected second id for fist iter to be _id2")
	}

	_id21, _ := id.FromHex(_id2.String())
	_id21.SetVersion(3)
	if err := i.Index(_id21, map[string]interface{}{"letter": "z"}); err != nil {
		panic(err)
	}

	_ids2, cursor2, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids2=%q\ncursor2=%v\n", _ids2, cursor2)
	if len(_ids2) != 2 {
		t.Errorf("expected 2 _ids2 at second iter, got %d", len(_ids2))
	}
	if _ids2[0].String() != _id21.String() || _ids2[0].Version() != _id21.Version() {
		t.Errorf("expected first id for second iter to be _id21")
	}
	if _ids2[1].String() != _id1.String() || _ids2[1].Version() != _id1.Version() {
		t.Errorf("expected second id for second iter to be _id1")
	}

	_ids3, cursor3, err := i.Iter("lol", "", 50, 2)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids3=%q\ncursor3=%v\n", _ids3, cursor3)

	if len(_ids3) != 2 {
		t.Errorf("expected 2 _ids at third iter, got %d", len(_ids3))
	}
	if _ids3[0].String() != _id1.String() || _ids3[0].Version() != _id1.Version() {
		t.Errorf("expected first id for third iter to be _id1")
	}
	if _ids3[1].String() != _id2.String() || _ids3[1].Version() != _id2.Version() {
		t.Errorf("expected second id for third iter to be _id2")
	}
}
<commit_msg>docstore: fix tests<commit_after>package docstore

import (
	"testing"

	"a4.io/blobstash/pkg/config"
	"a4.io/blobstash/pkg/docstore/id"
)

func testConf() *config.Config {
	return &config.Config{
		DataDir: ".",
	}
}

func TestIndexBasic(t *testing.T) {
	i, err := newSortIndex(testConf(), "name", "name")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()
	_id, _ := id.New(3)
	v := buildVal(1, _id)
	t.Logf("v=%+v\n", v)
	s, _id2 := parseVal(v)
	if s != 1 {
		t.Errorf("failed to parse start, got %q, expected 1", s)
	}
	if _id2.String() != _id.String() {
		t.Errorf("failed to parse ID, got %v, expected %v", _id2.String(), _id.String())
	}
}

func TestBuildIndexKey(t *testing.T) {
	k := buildKey("lol")
	t.Logf("k=%+v\n", k)
}

func TestIndex(t *testing.T) {
	i, err := newSortIndex(testConf(), "letter", "letter")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()

	_id1, _ := id.New(1)
	_id1.SetVersion(1)
	if err := i.Index(_id1, map[string]interface{}{"letter": "adeeee"}); err != nil {
		panic(err)
	}

	_id2, _ := id.New(2)
	_id2.SetVersion(2)
	if err := i.Index(_id2, map[string]interface{}{"letter": "aa"}); err != nil {
		panic(err)
	}

	_ids, cursor, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids=%q\ncursor=%v\n", _ids, cursor)

	if len(_ids) != 2 {
		t.Errorf("expected 2 _ids at first iter, got %d", len(_ids))
	}
	if _ids[0].String() != _id1.String() || _ids[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fist iter to be _id1")
	}
	if _ids[1].String() != _id2.String() || _ids[1].Version() != _id2.Version() {
		t.Errorf("expected second id for fist iter to be _id2")
	}

	_id21, _ := id.FromHex(_id2.String())
	_id21.SetVersion(3)
	if err := i.Index(_id21, map[string]interface{}{"letter": "z"}); err != nil {
		panic(err)
	}

	_ids2, cursor2, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids2=%q\ncursor2=%v\n", _ids2, cursor2)
	if len(_ids2) != 2 {
		t.Errorf("expected 2 _ids2 at second iter, got %d", len(_ids2))
	}
	if _ids2[0].String() != _id21.String() || _ids2[0].Version() != _id21.Version() {
		t.Errorf("expected first id for second iter to be _id21")
	}
	if _ids2[1].String() != _id1.String() || _ids2[1].Version() != _id1.Version() {
		t.Errorf("expected second id for second iter to be _id1")
	}

	_ids3, cursor3, err := i.Iter("lol", "", 50, 2)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids3=%q\ncursor3=%v\n", _ids3, cursor3)

	if len(_ids3) != 2 {
		t.Errorf("expected 2 _ids at third iter, got %d", len(_ids3))
	}
	if _ids3[0].String() != _id1.String() || _ids3[0].Version() != _id1.Version() {
		t.Errorf("expected first id for third iter to be _id1")
	}
	if _ids3[1].String() != _id2.String() || _ids3[1].Version() != _id2.Version() {
		t.Errorf("expected second id for third iter to be _id2")
	}

	_id2.SetVersion(4)
	_id2.SetFlag(flagDeleted)

	if err := i.Index(_id2, nil); err != nil {
		panic(err)
	}

	_ids4, cursor4, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids4=%q\ncursor4=%v\n", _ids4, cursor4)

	if len(_ids4) != 1 {
		t.Errorf("expected 1 _ids at fourth iter, got %d", len(_ids3))
	}
	if _ids4[0].String() != _id1.String() || _ids4[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fourth iter to be _id1")
	}
}

func TestIndexUpdatedField(t *testing.T) {
	i, err := newSortIndex(testConf(), "letter", "_updated")
	if err != nil {
		panic(err)
	}
	defer i.Close()
	defer i.db.Destroy()

	_id1, _ := id.New(2)
	_id1.SetVersion(2)
	if err := i.Index(_id1, map[string]interface{}{"letter": "adeeee"}); err != nil {
		panic(err)
	}

	_id2, _ := id.New(1)
	_id2.SetVersion(1)
	if err := i.Index(_id2, map[string]interface{}{"letter": "aa"}); err != nil {
		panic(err)
	}

	_ids, cursor, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids=%q\ncursor=%v\n", _ids, cursor)

	if len(_ids) != 2 {
		t.Errorf("expected 2 _ids at first iter, got %d", len(_ids))
	}
	if _ids[0].String() != _id1.String() || _ids[0].Version() != _id1.Version() {
		t.Errorf("expected first id for fist iter to be _id1")
	}
	if _ids[1].String() != _id2.String() || _ids[1].Version() != _id2.Version() {
		t.Errorf("expected second id for fist iter to be _id2")
	}

	_id21, _ := id.FromHex(_id2.String())
	_id21.SetVersion(3)
	if err := i.Index(_id21, map[string]interface{}{"letter": "z"}); err != nil {
		panic(err)
	}

	_ids2, cursor2, err := i.Iter("lol", "", 50, 0)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids2=%q\ncursor2=%v\n", _ids2, cursor2)
	if len(_ids2) != 2 {
		t.Errorf("expected 2 _ids2 at second iter, got %d", len(_ids2))
	}
	if _ids2[0].String() != _id21.String() || _ids2[0].Version() != _id21.Version() {
		t.Errorf("expected first id for second iter to be _id21")
	}
	if _ids2[1].String() != _id1.String() || _ids2[1].Version() != _id1.Version() {
		t.Errorf("expected second id for second iter to be _id1")
	}

	_ids3, cursor3, err := i.Iter("lol", "", 50, 2)
	if err != nil {
		panic(err)
	}
	t.Logf("_ids3=%q\ncursor3=%v\n", _ids3, cursor3)

	if len(_ids3) != 2 {
		t.Errorf("expected 2 _ids at third iter, got %d", len(_ids3))
	}
	if _ids3[0].String() != _id1.String() || _ids3[0].Version() != _id1.Version() {
		t.Errorf("expected first id for third iter to be _id1")
	}
	if _ids3[1].String() != _id2.String() || _ids3[1].Version() != _id2.Version() {
		t.Errorf("expected second id for third iter to be _id2")
	}
}
<|endoftext|>


<commit_before>package cockroach

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	// Pull in the postgres database driver
)

// Store is an implementation of dss.Store using
// Cockroach DB as its backend store.
type Store struct {
	*sql.DB
}

// Dial returns a Store instance connected to a cockroach instance available at
// "uri".
// https://www.cockroachlabs.com/docs/stable/connection-parameters.html
func Dial(uri string) (*Store, error) {
	db, err := sql.Open("postgres", uri)
	if err != nil {
		return nil, err
	}

	return &Store{
		DB: db,
	}, nil
}

func BuildURI(params map[string]string) (string, error) {
	h := params["host"]
	if h == "" {
		return "", errors.New("missing crdb hostname")
	}
	p := params["port"]
	if p == "" {
		return "", errors.New("missing crdb port")
	}
	u := params["user"]
	if u == "" {
		return "", errors.New("missing crdb user")
	}
	ssl := params["ssl_mode"]
	if ssl == "" {
		return "", errors.New("missing crdb ssl_mode")
	}
	if ssl == "disable" {
		return fmt.Sprintf("postgresql://%s@%s:%s?sslmode=disable", u, h, p), nil
	}
	dir := params["ssl_dir"]
	if dir == "" {
		return "", errors.New("missing crdb ssl_dir")
	}
	return fmt.Sprintf("postgresql://%s@%s:%s?sslmode=%s&sslrootcert=%s/ca.crt&sslcert=%s/client.%s.crt&sslkey=%s/client.%s.crt", u, h, p, ssl, dir, dir, u, dir, u), nil
}

type queryable interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}

// Close closes the underlying DB connection.
func (s *Store) Close() error {
	return s.DB.Close()
}

// Bootstrap bootstraps the underlying database with required tables.
//
// TODO: We should handle database migrations properly, but bootstrap both us
// *and* the database with this manual approach here.
func (s *Store) Bootstrap(ctx context.Context) error {
	const query = `
	CREATE TABLE IF NOT EXISTS subscriptions (
		id UUID PRIMARY KEY,
		owner STRING NOT NULL,
		url STRING NOT NULL,
		notification_index INT4 DEFAULT 0,
		starts_at TIMESTAMPTZ,
		ends_at TIMESTAMPTZ,
		updated_at TIMESTAMPTZ NOT NULL,
		INDEX starts_at_idx (starts_at),
		INDEX ends_at_idx (ends_at),
		CHECK (starts_at IS NULL OR ends_at IS NULL OR starts_at < ends_at)
	);
	CREATE TABLE IF NOT EXISTS cells_subscriptions (
		cell_id INT64 NOT NULL,
		cell_level INT CHECK (cell_level BETWEEN 0 and 30),
		subscription_id UUID NOT NULL REFERENCES subscriptions (id) ON DELETE CASCADE,
		PRIMARY KEY (cell_id, subscription_id),
		INDEX cell_id_idx (cell_id),
		INDEX subscription_id_idx (subscription_id)
	);
	CREATE TABLE IF NOT EXISTS identification_service_areas (
		id UUID PRIMARY KEY,
		owner STRING NOT NULL,
		url STRING NOT NULL,
		starts_at TIMESTAMPTZ,
		ends_at TIMESTAMPTZ,
		updated_at TIMESTAMPTZ NOT NULL,
		INDEX starts_at_idx (starts_at),
		INDEX ends_at_idx (ends_at),
		INDEX updated_at_idx (updated_at),
		CHECK (starts_at IS NULL OR ends_at IS NULL OR starts_at < ends_at)
	);
	CREATE TABLE IF NOT EXISTS cells_identification_service_areas (
		cell_id INT64 NOT NULL,
		cell_level INT CHECK (cell_level BETWEEN 0 and 30),
		identification_service_area_id UUID NOT NULL REFERENCES identification_service_areas (id) ON DELETE CASCADE,
		PRIMARY KEY (cell_id, identification_service_area_id),
		INDEX cell_id_idx (cell_id),
		INDEX identification_service_area_id_idx (identification_service_area_id)
	);
	`
	_, err := s.ExecContext(ctx, query)
	return err
}

// cleanUp drops all required tables from the store, useful for testing.
func (s *Store) cleanUp(ctx context.Context) error {
	const query = `
	DROP TABLE IF EXISTS cells_subscriptions;
	DROP TABLE IF EXISTS subscriptions;
	DROP TABLE IF EXISTS cells_identification_service_areas;
	DROP TABLE IF EXISTS identification_service_areas;`

	_, err := s.ExecContext(ctx, query)
	return err
}
<commit_msg>Add index for column owner (#38)<commit_after>package cockroach

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	// Pull in the postgres database driver
)

// Store is an implementation of dss.Store using
// Cockroach DB as its backend store.
type Store struct {
	*sql.DB
}

// Dial returns a Store instance connected to a cockroach instance available at
// "uri".
// https://www.cockroachlabs.com/docs/stable/connection-parameters.html
func Dial(uri string) (*Store, error) {
	db, err := sql.Open("postgres", uri)
	if err != nil {
		return nil, err
	}

	return &Store{
		DB: db,
	}, nil
}

func BuildURI(params map[string]string) (string, error) {
	h := params["host"]
	if h == "" {
		return "", errors.New("missing crdb hostname")
	}
	p := params["port"]
	if p == "" {
		return "", errors.New("missing crdb port")
	}
	u := params["user"]
	if u == "" {
		return "", errors.New("missing crdb user")
	}
	ssl := params["ssl_mode"]
	if ssl == "" {
		return "", errors.New("missing crdb ssl_mode")
	}
	if ssl == "disable" {
		return fmt.Sprintf("postgresql://%s@%s:%s?sslmode=disable", u, h, p), nil
	}
	dir := params["ssl_dir"]
	if dir == "" {
		return "", errors.New("missing crdb ssl_dir")
	}
	return fmt.Sprintf("postgresql://%s@%s:%s?sslmode=%s&sslrootcert=%s/ca.crt&sslcert=%s/client.%s.crt&sslkey=%s/client.%s.crt", u, h, p, ssl, dir, dir, u, dir, u), nil
}

type queryable interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}

// Close closes the underlying DB connection.
func (s *Store) Close() error {
	return s.DB.Close()
}

// Bootstrap bootstraps the underlying database with required tables.
//
// TODO: We should handle database migrations properly, but bootstrap both us
// *and* the database with this manual approach here.
func (s *Store) Bootstrap(ctx context.Context) error {
	const query = `
	CREATE TABLE IF NOT EXISTS subscriptions (
		id UUID PRIMARY KEY,
		owner STRING NOT NULL,
		url STRING NOT NULL,
		notification_index INT4 DEFAULT 0,
		starts_at TIMESTAMPTZ,
		ends_at TIMESTAMPTZ,
		updated_at TIMESTAMPTZ NOT NULL,
		INDEX owner_idx (owner),
		INDEX starts_at_idx (starts_at),
		INDEX ends_at_idx (ends_at),
		CHECK (starts_at IS NULL OR ends_at IS NULL OR starts_at < ends_at)
	);
	CREATE TABLE IF NOT EXISTS cells_subscriptions (
		cell_id INT64 NOT NULL,
		cell_level INT CHECK (cell_level BETWEEN 0 and 30),
		subscription_id UUID NOT NULL REFERENCES subscriptions (id) ON DELETE CASCADE,
		PRIMARY KEY (cell_id, subscription_id),
		INDEX cell_id_idx (cell_id),
		INDEX subscription_id_idx (subscription_id)
	);
	CREATE TABLE IF NOT EXISTS identification_service_areas (
		id UUID PRIMARY KEY,
		owner STRING NOT NULL,
		url STRING NOT NULL,
		starts_at TIMESTAMPTZ,
		ends_at TIMESTAMPTZ,
		updated_at TIMESTAMPTZ NOT NULL,
		INDEX owner_idx (owner),
		INDEX starts_at_idx (starts_at),
		INDEX ends_at_idx (ends_at),
		INDEX updated_at_idx (updated_at),
		CHECK (starts_at IS NULL OR ends_at IS NULL OR starts_at < ends_at)
	);
	CREATE TABLE IF NOT EXISTS cells_identification_service_areas (
		cell_id INT64 NOT NULL,
		cell_level INT CHECK (cell_level BETWEEN 0 and 30),
		identification_service_area_id UUID NOT NULL REFERENCES identification_service_areas (id) ON DELETE CASCADE,
		PRIMARY KEY (cell_id, identification_service_area_id),
		INDEX cell_id_idx (cell_id),
		INDEX identification_service_area_id_idx (identification_service_area_id)
	);
	`
	_, err := s.ExecContext(ctx, query)
	return err
}

// cleanUp drops all required tables from the store, useful for testing.
func (s *Store) cleanUp(ctx context.Context) error {
	const query = `
	DROP TABLE IF EXISTS cells_subscriptions;
	DROP TABLE IF EXISTS subscriptions;
	DROP TABLE IF EXISTS cells_identification_service_areas;
	DROP TABLE IF EXISTS identification_service_areas;`

	_, err := s.ExecContext(ctx, query)
	return err
}
<|endoftext|>


<commit_before>// Package spigot implements Spigot algorithm for Pi and E
package spigot

const backlog = 10 // backlog value for buffered channel

// spigot step
func spigot(a, r, q int, carry <-chan int) <-chan int {
	c := make(chan int, backlog)
	go func() {
		for cr := range carry {
			a = 10*a + cr
			c <- r * (a / q)
			a %= q
		}
		close(c)
	}()
	return c
}

// seed initial values (zero)
func seed(n int) <-chan int {
	c := make(chan int)
	go func() {
		for i := 0; i < n; i++ {
			c <- 0
		}
		close(c)
	}()
	return c
}

// Pi calculates n digits of Pi
//
// 1. Initialize: Let A = (2, 2, 2, 2,... ,2) be an array of length
//    [10n/3]+1.
//
// 2. Repeat n times:
//
//    Multiply by 10: Multiply each entry of A by 10.
//
//    Put A into regular form: Starting from the right, reduce the
//    ith element of A (corresponding to b-entry (i - 1)/(2i - 1))
//    modulo 2i - 1, to get a quotient q and a remainder r. Leave
//    r in place and carry q(i - 1) one place left. The last integer
//    carried (from the position where i - 1 = 2) may be as large
//    as 19.
//
// 3. Get the next predigit: Reduce the leftmost entry of A (which
//    is at most 109 (= 9 - 10 + 191)) modulo 10. The quotient, q,
//    is the new predigit of π, the remainder staying in place.
//
// 4. Adjust the predigits: If q is neither 9 nor 10, release the
//    held predigits as true digits of π and hold q. If q is 9, add
//    q to the queue of held predigits. If q is 10 then:
//
//    - set the current predigit to 0 and hold it;
//    - increase all other held predigits by 1(9 becomes 0);
//    - release as true digits of π all but the current held predigit.
//
func Pi(n int) <-chan int {
	c := seed(n + 1)
	for i := 10*n/3 + 1; i > 0; i-- {
		c = spigot(2, i, 2*i+1, c)
	}
	return predigit(spigot(2, 1, 10, c))
}

func predigit(in <-chan int) <-chan int {
	c := make(chan int)
	drain := func(pre []int, i int) {
		for _, v := range pre {
			c <- (v + i) % 10
		}
	}
	go func() {
		var pre []int
		for i := range in {
			switch i {
			case 9:
				pre = append(pre, i)
			case 10:
				drain(pre, 1)
				pre = append(pre[:0], i%10)
			default:
				drain(pre, 0)
				pre = append(pre[:0], i%10)
			}
		}
		drain(pre, 0)
		close(c)
	}()
	return c
}

// E calculates n digits of E
//
// 1. Initialize: Let the first digit be 2 and initialize an array
//    A of length n + 1 to (1, 1, 1, . . . , 1).
//
// 2. Repeat n − 1 times:
//
//    Multiply by 10: Multiply each entry of A by 10.
//
//    Take the fractional part: Starting from the right, reduce the
//    ith entry of A modulo i + 1, carrying the quotient one place
//    left.
//
//    Output the next digit: The final quotient is the next digit of e.
//
func E(n int) <-chan int {
	c := seed(n + 1)
	for i := n + 1; i > 0; i-- {
		c = spigot(1, 1, i+1, c)
	}
	return spigot(2, 1, 10, c)
}
<commit_msg>Fix godoc formatting<commit_after>// Package spigot implements Spigot algorithm for Pi and E
package spigot

const backlog = 10 // backlog value for buffered channel

// spigot step
func spigot(a, r, q int, carry <-chan int) <-chan int {
	c := make(chan int, backlog)
	go func() {
		for cr := range carry {
			a = 10*a + cr
			c <- r * (a / q)
			a %= q
		}
		close(c)
	}()
	return c
}

// seed initial values (zero)
func seed(n int) <-chan int {
	c := make(chan int)
	go func() {
		for i := 0; i < n; i++ {
			c <- 0
		}
		close(c)
	}()
	return c
}

// Pi calculates n digits of Pi
//
//  1. Initialize: Let A = (2, 2, 2, 2,... ,2) be an array of length
//     [10n/3]+1.
//
//  2. Repeat n times:
//
//     Multiply by 10: Multiply each entry of A by 10.
//
//     Put A into regular form: Starting from the right, reduce the
//     ith element of A (corresponding to b-entry (i - 1)/(2i - 1))
//     modulo 2i - 1, to get a quotient q and a remainder r. Leave
//     r in place and carry q(i - 1) one place left. The last integer
//     carried (from the position where i - 1 = 2) may be as large
//     as 19.
//
//  3. Get the next predigit: Reduce the leftmost entry of A (which
//     is at most 109 (= 9 - 10 + 191)) modulo 10. The quotient, q,
//     is the new predigit of π, the remainder staying in place.
//
//  4. Adjust the predigits: If q is neither 9 nor 10, release the
//     held predigits as true digits of π and hold q. If q is 9, add
//     q to the queue of held predigits. If q is 10 then:
//
//     - set the current predigit to 0 and hold it;
//     - increase all other held predigits by 1(9 becomes 0);
//     - release as true digits of π all but the current held predigit.
//
func Pi(n int) <-chan int {
	c := seed(n + 1)
	for i := 10*n/3 + 1; i > 0; i-- {
		c = spigot(2, i, 2*i+1, c)
	}
	return predigit(spigot(2, 1, 10, c))
}

func predigit(in <-chan int) <-chan int {
	c := make(chan int)
	drain := func(pre []int, i int) {
		for _, v := range pre {
			c <- (v + i) % 10
		}
	}
	go func() {
		var pre []int
		for i := range in {
			switch i {
			case 9:
				pre = append(pre, i)
			case 10:
				drain(pre, 1)
				pre = append(pre[:0], i%10)
			default:
				drain(pre, 0)
				pre = append(pre[:0], i%10)
			}
		}
		drain(pre, 0)
		close(c)
	}()
	return c
}

// E calculates n digits of E
//
//  1. Initialize: Let the first digit be 2 and initialize an array
//     A of length n + 1 to (1, 1, 1, . . . , 1).
//
//  2. Repeat n − 1 times:
//
//     Multiply by 10: Multiply each entry of A by 10.
//
//     Take the fractional part: Starting from the right, reduce the
//     ith entry of A modulo i + 1, carrying the quotient one place
//     left.
//
//     Output the next digit: The final quotient is the next digit of e.
//
func E(n int) <-chan int {
	c := seed(n + 1)
	for i := n + 1; i > 0; i-- {
		c = spigot(1, 1, i+1, c)
	}
	return spigot(2, 1, 10, c)
}
<|endoftext|>


<commit_before>package file

import (
	"math/big"
	"os"
	"strconv"

	"src.elv.sh/pkg/eval"
	"src.elv.sh/pkg/eval/errs"
	"src.elv.sh/pkg/eval/vals"
)

var Ns = eval.NsBuilder{}.AddGoFns("file:", fns).Ns()

var fns = map[string]interface{}{
	"close":    close,
	"open":     open,
	"pipe":     pipe,
	"truncate": truncate,
}

//elvdoc:fn open
//
// ```elvish
// file:open $filename
// ```
//
// Opens a file. Currently, `open` only supports opening a file for reading.
// File must be closed with `close` explicitly. Example:
//
// ```elvish-transcript
// ~> cat a.txt
// This is
// a file.
// ~> use file
// ~> f = (file:open a.txt)
// ~> cat < $f
// This is
// a file.
// ~> close $f
// ```
//
// @cf close

func open(name string) (vals.File, error) {
	return os.Open(name)
}

//elvdoc:fn close
//
// ```elvish
// ~> file:close $file
// ```
//
// Closes a file opened with `open`.
//
// @cf open

func close(f vals.File) error {
	return f.Close()
}

//elvdoc:fn pipe
//
// ```elvish
// file:pipe
// ```
//
// Create a new pipe that can be used in redirections. A pipe contains a read-end and write-end.
// Each pipe object is a [pseudo-map](#pseudo-map) with fields `r` (the read-end [file
// object](./language.html#file)) and `w` (the write-end).

// When redirecting command input from a pipe with `<`, the read-end is used. When redirecting
// command output to a pipe with `>`, the write-end is used. Redirecting both input and output with
// `<>` to a pipe is not supported.
//
// Pipes have an OS-dependent buffer, so writing to a pipe without an active reader
// does not necessarily block. Pipes **must** be explicitly closed with `file:close`.
//
// Putting values into pipes will cause those values to be discarded.
//
// Examples (assuming the pipe has a large enough buffer):
//
// ```elvish-transcript
// ~> p = (file:pipe)
// ~> echo 'lorem ipsum' > $p
// ~> head -n1 < $p
// lorem ipsum
// ~> put 'lorem ipsum' > $p
// ~> file:close $p[w] # close the write-end
// ~> head -n1 < $p # blocks unless the write-end is closed
// ~> file:close $p[r] # close the read-end
// ```
//
// @cf close

func pipe() (vals.Pipe, error) {
	r, w, err := os.Pipe()
	return vals.NewPipe(r, w), err
}

//elvdoc:fn truncate
//
// ```elvish
// file:truncate $filename $size
// ```
//
// changes the size of the named file. If the file is a symbolic link, it
// changes the size of the link's target. The size must be an integer between 0
// and 2^64-1.

func truncate(name string, rawSize vals.Num) error {
	var size int64
	switch rawSize := rawSize.(type) {
	case int:
		size = int64(rawSize)
	case *big.Int:
		if rawSize.IsInt64() {
			size = rawSize.Int64()
		} else {
			return truncateSizeOutOfRange(rawSize.String())
		}
	default:
		return errs.BadValue{
			What:  "size argument to file:truncate",
			Valid: "integer", Actual: "non-integer",
		}
	}
	if size < 0 {
		return truncateSizeOutOfRange(strconv.FormatInt(size, 10))
	}
	return os.Truncate(name, size)
}

func truncateSizeOutOfRange(size string) error {
	return errs.OutOfRange{
		What:      "size argument to file:truncate",
		ValidLow:  "0",
		ValidHigh: "2^64-1",
		Actual:    size,
	}
}
<commit_msg>Fix the file module's elvdoc.<commit_after>package file

import (
	"math/big"
	"os"
	"strconv"

	"src.elv.sh/pkg/eval"
	"src.elv.sh/pkg/eval/errs"
	"src.elv.sh/pkg/eval/vals"
)

var Ns = eval.NsBuilder{}.AddGoFns("file:", fns).Ns()

var fns = map[string]interface{}{
	"close":    close,
	"open":     open,
	"pipe":     pipe,
	"truncate": truncate,
}

//elvdoc:fn open
//
// ```elvish
// file:open $filename
// ```
//
// Opens a file. Currently, `open` only supports opening a file for reading.
// File must be closed with `close` explicitly. Example:
//
// ```elvish-transcript
// ~> cat a.txt
// This is
// a file.
// ~> use file
// ~> f = (file:open a.txt)
// ~> cat < $f
// This is
// a file.
// ~> close $f
// ```
//
// @cf file:close

func open(name string) (vals.File, error) {
	return os.Open(name)
}

//elvdoc:fn close
//
// ```elvish
// ~> file:close $file
// ```
//
// Closes a file opened with `open`.
//
// @cf file:open

func close(f vals.File) error {
	return f.Close()
}

//elvdoc:fn pipe
//
// ```elvish
// file:pipe
// ```
//
// Create a new pipe that can be used in redirections. A pipe contains a read-end and write-end.
// Each pipe object is a [pseudo-map](#pseudo-map) with fields `r` (the read-end [file
// object](./language.html#file)) and `w` (the write-end).
//
// When redirecting command input from a pipe with `<`, the read-end is used. When redirecting
// command output to a pipe with `>`, the write-end is used. Redirecting both input and output with
// `<>` to a pipe is not supported.
//
// Pipes have an OS-dependent buffer, so writing to a pipe without an active reader
// does not necessarily block. Pipes **must** be explicitly closed with `file:close`.
//
// Putting values into pipes will cause those values to be discarded.
//
// Examples (assuming the pipe has a large enough buffer):
//
// ```elvish-transcript
// ~> p = (file:pipe)
// ~> echo 'lorem ipsum' > $p
// ~> head -n1 < $p
// lorem ipsum
// ~> put 'lorem ipsum' > $p
// ~> file:close $p[w] # close the write-end
// ~> head -n1 < $p # blocks unless the write-end is closed
// ~> file:close $p[r] # close the read-end
// ```
//
// @cf file:close

func pipe() (vals.Pipe, error) {
	r, w, err := os.Pipe()
	return vals.NewPipe(r, w), err
}

//elvdoc:fn truncate
//
// ```elvish
// file:truncate $filename $size
// ```
//
// changes the size of the named file. If the file is a symbolic link, it
// changes the size of the link's target. The size must be an integer between 0
// and 2^64-1.

func truncate(name string, rawSize vals.Num) error {
	var size int64
	switch rawSize := rawSize.(type) {
	case int:
		size = int64(rawSize)
	case *big.Int:
		if rawSize.IsInt64() {
			size = rawSize.Int64()
		} else {
			return truncateSizeOutOfRange(rawSize.String())
		}
	default:
		return errs.BadValue{
			What:  "size argument to file:truncate",
			Valid: "integer", Actual: "non-integer",
		}
	}
	if size < 0 {
		return truncateSizeOutOfRange(strconv.FormatInt(size, 10))
	}
	return os.Truncate(name, size)
}

func truncateSizeOutOfRange(size string) error {
	return errs.OutOfRange{
		What:      "size argument to file:truncate",
		ValidLow:  "0",
		ValidHigh: "2^64-1",
		Actual:    size,
	}
}
<|endoftext|>


<commit_before>package dataio

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/soniakeys/meeus/julian"
)

// CgCatalog definiton.
type CgCatalog struct {
	Version string     `json:"version"`
	Name    string     `json:"name"`
	Items   []*CgItems `json:"items"`
	Require []*string  `json:"require"`
}

func (c *CgCatalog) String() string {
	return c.Name + "(" + c.Version + ")"
}

// CgItems definiton.
type CgItems struct {
	Class          string            `json:"class"`
	Name           string            `json:"name"`
	StartTime      string            `json:"startTime"`
	EndTime        string            `json:"endTime"`
	Center         string            `json:"center"`
	Trajectory     *CgTrajectory     `json:"trajectory"`
	Bodyframe      *CgBodyFrame      `json:"bodyFrame"`
	Geometry       *CgGeometry       `json:"geometry"`
	Label          *CgLabel          `json:"label"`
	TrajectoryPlot *CgTrajectoryPlot `json:"trajectoryPlot"`
}

// CgTrajectory definition.
type CgTrajectory struct {
	Type   string `json:"type"`
	Source string `json:"source"`
}

// Validate validates a CgTrajectory.
func (t *CgTrajectory) Validate() error {
	if t.Type != "InterpolatedStates" || !strings.HasSuffix(t.Source, "xyzv") {
		return errors.New("Only InterpolatedStates are currently supported in Cosmographia trajectory types.")
	}
	return nil
}

func (t *CgTrajectory) String() string {
	return t.Source + " as " + t.Type
}

// CgBodyFrame definiton.
type CgBodyFrame struct {
	Type string `json:"type"`
	Name string `json:"name"`
}

func (c *CgBodyFrame) String() string {
	return c.Name + " (type: " + c.Type + ")"
}

// CgGeometry definiton.
type CgGeometry struct {
	Type   string    `json:"type"`
	Mesh   []float64 `json:"meshRotation"`
	Size   float64   `json:"size"`
	Source string    `json:"source"`
}

// CgLabel definiton.
type CgLabel struct {
	Color    []float64 `json:"color"`
	FadeSize int       `json:"fadeSize"`
	ShowText bool      `json:"showText"`
}

func (l *CgLabel) String() string {
	return fmt.Sprintf("color %v, fade %d, show %v", l.Color, l.FadeSize, l.ShowText)
}

// CgTrajectoryPlot definition.
type CgTrajectoryPlot struct {
	Color       []float64 `json:"color"`
	LineWidth   int       `json:"lineWidth"`
	Duration    string    `json:"duration"`
	Lead        string    `json:"lead"`
	Fade        int       `json:"fade"`
	SampleCount int       `json:"sampleCount"`
}

// CgInterpolatedState definiton.
type CgInterpolatedState struct {
	JD       float64
	Position []float64
	Velocity []float64
}

// FromText initializes from text.
// The `record` parameter must be an array of seven items.
func (i *CgInterpolatedState) FromText(record []string) {
	if val, err := strconv.ParseFloat(record[0], 64); err != nil {
		panic(err)
	} else {
		i.JD = val
	}

	if posX, err := strconv.ParseFloat(record[1], 64); err != nil {
		panic(err)
	} else if posY, err := strconv.ParseFloat(record[2], 64); err != nil {
		panic(err)
	} else if posZ, err := strconv.ParseFloat(record[3], 64); err != nil {
		panic(err)
	} else {
		i.Position = []float64{posX, posY, posZ}
	}

	if velX, err := strconv.ParseFloat(record[4], 64); err != nil {
		panic(err)
	} else if velY, err := strconv.ParseFloat(record[5], 64); err != nil {
		panic(err)
	} else if velZ, err := strconv.ParseFloat(record[6], 64); err != nil {
		panic(err)
	} else {
		i.Velocity = []float64{velX, velY, velZ}
	}
}

// ToText converts to text for written output.
func (i *CgInterpolatedState) ToText() string {
	return fmt.Sprintf("%f %f %f %f %f %f %f", i.JD, i.Position[0], i.Position[1], i.Position[2], i.Velocity[0], i.Velocity[1], i.Velocity[2])
}

// ParseInterpolatedStates takes a string and converts that into a CgInterpolatedState.
func ParseInterpolatedStates(s string) []*CgInterpolatedState {
	var states = []*CgInterpolatedState{}
	r := csv.NewReader(strings.NewReader(s))
	r.Comma = ' '
	r.Comment = '#'
	for {
		record, err := r.Read()
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}
		state := CgInterpolatedState{}
		state.FromText(record)
		states = append(states, &state)
	}

	return states
}

// StreamInterpolatedStates streams the output of the channel to the provided file.
func StreamInterpolatedStates(filename string, histChan <-chan (*CgInterpolatedState), stamped bool) {
	if stamped {
		t := time.Now()
		filename = fmt.Sprintf("%s-%d-%02d-%02dT%02d.%02d.%02d.xyzv", filename, t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	} else {
		filename = fmt.Sprintf("%s.xyzv", filename)
	}
	f, err := os.Create(filename)
	fmt.Printf("Saving file to %s.\n", f.Name())
	if err != nil {
		panic(err)
	}
	defer f.Close()
	// Header
	f.WriteString(fmt.Sprintf(`# Creation date (UTC): %s
# Records are <jd> <x> <y> <z> <vel x> <vel y> <vel z>
#   Time is a TDB Julian date
#   Position in km
#   Velocity in km/sec`, time.Now()))
	// Read from channel
	previousJD := 0.0
	for {
		state, more := <-histChan
		if more {
			// Only write one data point per julian second.
			if state.JD-previousJD < 1e-6 {
				continue
			} else if previousJD == 0 {
				// First iteration, let's add the initial time in simulation.
				f.WriteString(fmt.Sprintf("\n# Simulation time start (UTC): %s", julian.JDToTime(state.JD).UTC()))
			}
			previousJD = state.JD
			_, err := f.WriteString("\n" + state.ToText())
			if err != nil {
				panic(err)
			}
		} else {
			f.WriteString(fmt.Sprintf("\n# Simulation time end (UTC): %s\n", julian.JDToTime(previousJD).UTC()))
			return
		}
	}
}
<commit_msg>Change export to have one data point per minute.<commit_after>package dataio

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/soniakeys/meeus/julian"
)

// CgCatalog definiton.
type CgCatalog struct {
	Version string     `json:"version"`
	Name    string     `json:"name"`
	Items   []*CgItems `json:"items"`
	Require []*string  `json:"require"`
}

func (c *CgCatalog) String() string {
	return c.Name + "(" + c.Version + ")"
}

// CgItems definiton.
type CgItems struct {
	Class          string            `json:"class"`
	Name           string            `json:"name"`
	StartTime      string            `json:"startTime"`
	EndTime        string            `json:"endTime"`
	Center         string            `json:"center"`
	Trajectory     *CgTrajectory     `json:"trajectory"`
	Bodyframe      *CgBodyFrame      `json:"bodyFrame"`
	Geometry       *CgGeometry       `json:"geometry"`
	Label          *CgLabel          `json:"label"`
	TrajectoryPlot *CgTrajectoryPlot `json:"trajectoryPlot"`
}

// CgTrajectory definition.
type CgTrajectory struct {
	Type   string `json:"type"`
	Source string `json:"source"`
}

// Validate validates a CgTrajectory.
func (t *CgTrajectory) Validate() error {
	if t.Type != "InterpolatedStates" || !strings.HasSuffix(t.Source, "xyzv") {
		return errors.New("Only InterpolatedStates are currently supported in Cosmographia trajectory types.")
	}
	return nil
}

func (t *CgTrajectory) String() string {
	return t.Source + " as " + t.Type
}

// CgBodyFrame definiton.
type CgBodyFrame struct {
	Type string `json:"type"`
	Name string `json:"name"`
}

func (c *CgBodyFrame) String() string {
	return c.Name + " (type: " + c.Type + ")"
}

// CgGeometry definiton.
type CgGeometry struct {
	Type   string    `json:"type"`
	Mesh   []float64 `json:"meshRotation"`
	Size   float64   `json:"size"`
	Source string    `json:"source"`
}

// CgLabel definiton.
type CgLabel struct {
	Color    []float64 `json:"color"`
	FadeSize int       `json:"fadeSize"`
	ShowText bool      `json:"showText"`
}

func (l *CgLabel) String() string {
	return fmt.Sprintf("color %v, fade %d, show %v", l.Color, l.FadeSize, l.ShowText)
}

// CgTrajectoryPlot definition.
type CgTrajectoryPlot struct {
	Color       []float64 `json:"color"`
	LineWidth   int       `json:"lineWidth"`
	Duration    string    `json:"duration"`
	Lead        string    `json:"lead"`
	Fade        int       `json:"fade"`
	SampleCount int       `json:"sampleCount"`
}

// CgInterpolatedState definiton.
type CgInterpolatedState struct {
	JD       float64
	Position []float64
	Velocity []float64
}

// FromText initializes from text.
// The `record` parameter must be an array of seven items.
func (i *CgInterpolatedState) FromText(record []string) {
	if val, err := strconv.ParseFloat(record[0], 64); err != nil {
		panic(err)
	} else {
		i.JD = val
	}

	if posX, err := strconv.ParseFloat(record[1], 64); err != nil {
		panic(err)
	} else if posY, err := strconv.ParseFloat(record[2], 64); err != nil {
		panic(err)
	} else if posZ, err := strconv.ParseFloat(record[3], 64); err != nil {
		panic(err)
	} else {
		i.Position = []float64{posX, posY, posZ}
	}

	if velX, err := strconv.ParseFloat(record[4], 64); err != nil {
		panic(err)
	} else if velY, err := strconv.ParseFloat(record[5], 64); err != nil {
		panic(err)
	} else if velZ, err := strconv.ParseFloat(record[6], 64); err != nil {
		panic(err)
	} else {
		i.Velocity = []float64{velX, velY, velZ}
	}
}

// ToText converts to text for written output.
func (i *CgInterpolatedState) ToText() string {
	return fmt.Sprintf("%f %f %f %f %f %f %f", i.JD, i.Position[0], i.Position[1], i.Position[2], i.Velocity[0], i.Velocity[1], i.Velocity[2])
}

// ParseInterpolatedStates takes a string and converts that into a CgInterpolatedState.
func ParseInterpolatedStates(s string) []*CgInterpolatedState {
	var states = []*CgInterpolatedState{}
	r := csv.NewReader(strings.NewReader(s))
	r.Comma = ' '
	r.Comment = '#'
	for {
		record, err := r.Read()
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}
		state := CgInterpolatedState{}
		state.FromText(record)
		states = append(states, &state)
	}

	return states
}

// StreamInterpolatedStates streams the output of the channel to the provided file.
func StreamInterpolatedStates(filename string, histChan <-chan (*CgInterpolatedState), stamped bool) {
	if stamped {
		t := time.Now()
		filename = fmt.Sprintf("%s-%d-%02d-%02dT%02d.%02d.%02d.xyzv", filename, t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	} else {
		filename = fmt.Sprintf("%s.xyzv", filename)
	}
	f, err := os.Create(filename)
	fmt.Printf("Saving file to %s.\n", f.Name())
	if err != nil {
		panic(err)
	}
	defer f.Close()
	// Header
	f.WriteString(fmt.Sprintf(`# Creation date (UTC): %s
# Records are <jd> <x> <y> <z> <vel x> <vel y> <vel z>
#   Time is a TDB Julian date
#   Position in km
#   Velocity in km/sec`, time.Now()))
	// Read from channel
	previousJD := 0.0
	for {
		state, more := <-histChan
		if more {
			// Only write one data point per julian minute.
			if state.JD-previousJD < 1.0/(24*60) {
				continue
			} else if previousJD == 0 {
				// First iteration, let's add the initial time in simulation.
				f.WriteString(fmt.Sprintf("\n# Simulation time start (UTC): %s", julian.JDToTime(state.JD).UTC()))
			}
			previousJD = state.JD
			_, err := f.WriteString("\n" + state.ToText())
			if err != nil {
				panic(err)
			}
		} else {
			f.WriteString(fmt.Sprintf("\n# Simulation time end (UTC): %s\n", julian.JDToTime(previousJD).UTC()))
			return
		}
	}
}
<|endoftext|>