<commit_before>//
// Copyright (c) 2017
// Mainflux
// Cavium
//
// SPDX-License-Identifier: Apache-2.0
//

package client

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/drasko/edgex-export"
	"github.com/drasko/edgex-export/mongo"
	"github.com/go-zoo/bone"
	"go.uber.org/zap"
	"gopkg.in/mgo.v2/bson"
)

func getRegByID(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	id := bone.GetValue(r, "id")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := export.Registration{}
	if err := c.Find(bson.M{"id": id}).One(&reg); err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func getRegList(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	t := bone.GetValue(r, "type")

	var l string

	switch t {
	case "algorithms":
		l = `["None","Aes"]`
	case "compressions":
		l = `["None","Gzip","Zip"]`
	case "formats":
		l = `["JSON","XML","Serialized","IotCoreJSON","AzureJSON","CSV"]`
	case "destinations":
		l = `["DestMQTT", "TeDestZMQller", "DestIotCoreMQTT,
			"DestAzureMQTT", "DestRest"]`
	default:
		logger.Error("Unknown type: " + t)
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "Unknown type: "+t)
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, l)
}

func getAllReg(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := []export.Registration{}
	if err := c.Find(nil).All(&reg); err != nil {
		logger.Error("Failed to query all registrations", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query all registrations", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func getRegByName(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	name := bone.GetValue(r, "name")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := export.Registration{}
	if err := c.Find(bson.M{"name": name}).One(&reg); err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func addReg(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	reg := export.Registration{}
	if err := json.Unmarshal(data, &reg); err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	count, err := c.Find(bson.M{"name": reg.Name}).Count()
	if err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}
	if count != 0 {
		logger.Error("Username already taken: " + reg.Name)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if err := c.Insert(reg); err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusCreated)
	notifyUpdatedRegistrations()
}

func updateReg(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	var body map[string]interface{}
	if err := json.Unmarshal(data, &body); err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
	}

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	name := body["name"]
	query := bson.M{"name": name}
	update := bson.M{"$set": body}

	if err := c.Update(query, update); err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func delRegByID(w http.ResponseWriter, r *http.Request) {
	id := bone.GetValue(r, "id")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	if err := c.Remove(bson.M{"id": id}); err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func delRegByName(w http.ResponseWriter, r *http.Request) {
	name := bone.GetValue(r, "name")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	if err := c.Remove(bson.M{"name": name}); err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func notifyUpdatedRegistrations() {
	go func() {
		// TODO make configurable distro host/port
		client := &http.Client{}
		req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:48070/api/v1/notify/registrations", nil)
		if err != nil {
			logger.Error("Error creating http request")
			return
		}
		_, err = client.Do(req)
		if err != nil {
			logger.Error("Error notifying updated registrations to distro")
		}
	}()
}
<commit_msg>Set host and port as const<commit_after>//
// Copyright (c) 2017
// Mainflux
// Cavium
//
// SPDX-License-Identifier: Apache-2.0
//

package client

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/drasko/edgex-export"
	"github.com/drasko/edgex-export/mongo"
	"github.com/go-zoo/bone"
	"go.uber.org/zap"
	"gopkg.in/mgo.v2/bson"
)

const (
	// TODO this consts need to be configurable somehow
	distroHost     = "127.0.0.1"
	distroPort int = 48070
)

func getRegByID(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	id := bone.GetValue(r, "id")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := export.Registration{}
	if err := c.Find(bson.M{"id": id}).One(&reg); err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func getRegList(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	t := bone.GetValue(r, "type")

	var l string

	switch t {
	case "algorithms":
		l = `["None","Aes"]`
	case "compressions":
		l = `["None","Gzip","Zip"]`
	case "formats":
		l = `["JSON","XML","Serialized","IotCoreJSON","AzureJSON","CSV"]`
	case "destinations":
		l = `["DestMQTT", "TeDestZMQller", "DestIotCoreMQTT,
			"DestAzureMQTT", "DestRest"]`
	default:
		logger.Error("Unknown type: " + t)
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "Unknown type: "+t)
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, l)
}

func getAllReg(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := []export.Registration{}
	if err := c.Find(nil).All(&reg); err != nil {
		logger.Error("Failed to query all registrations", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query all registrations", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func getRegByName(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	name := bone.GetValue(r, "name")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	reg := export.Registration{}
	if err := c.Find(bson.M{"name": name}).One(&reg); err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	res, err := json.Marshal(reg)
	if err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	io.WriteString(w, string(res))
}

func addReg(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	reg := export.Registration{}
	if err := json.Unmarshal(data, &reg); err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	count, err := c.Find(bson.M{"name": reg.Name}).Count()
	if err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}
	if count != 0 {
		logger.Error("Username already taken: " + reg.Name)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if err := c.Insert(reg); err != nil {
		logger.Error("Failed to query add registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusCreated)
	notifyUpdatedRegistrations()
}

func updateReg(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, err.Error())
		return
	}

	var body map[string]interface{}
	if err := json.Unmarshal(data, &body); err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
	}

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	name := body["name"]
	query := bson.M{"name": name}
	update := bson.M{"$set": body}

	if err := c.Update(query, update); err != nil {
		logger.Error("Failed to query update registration", zap.Error(err))
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func delRegByID(w http.ResponseWriter, r *http.Request) {
	id := bone.GetValue(r, "id")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	if err := c.Remove(bson.M{"id": id}); err != nil {
		logger.Error("Failed to query by id", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func delRegByName(w http.ResponseWriter, r *http.Request) {
	name := bone.GetValue(r, "name")

	s := repo.Session.Copy()
	defer s.Close()
	c := s.DB(mongo.DBName).C(mongo.CollectionName)

	if err := c.Remove(bson.M{"name": name}); err != nil {
		logger.Error("Failed to query by name", zap.Error(err))
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, err.Error())
		return
	}

	w.WriteHeader(http.StatusOK)
	notifyUpdatedRegistrations()
}

func notifyUpdatedRegistrations() {
	go func() {
		// TODO make configurable distro host/port
		client := &http.Client{}
		url := "http://" + distroHost + ":" + strconv.Itoa(distroPort) +
			"/api/v1/notify/registrations"
		req, err := http.NewRequest(http.MethodPut, url, nil)
		if err != nil {
			logger.Error("Error creating http request")
			return
		}
		_, err = client.Do(req)
		if err != nil {
			logger.Error("Error notifying updated registrations to distro", zap.String("url", url))
		}
	}()
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/go-swagger/go-swagger/client"
	"github.com/go-swagger/go-swagger/httpkit"
	"github.com/go-swagger/go-swagger/spec"
	"github.com/go-swagger/go-swagger/strfmt"
	"github.com/stretchr/testify/assert"
)

// task This describes a task. Tasks require a content property to be set.
type task struct {

	// Completed
	Completed bool `json:"completed"`

	// Content Task content can contain [GFM](https://help.github.com/articles/github-flavored-markdown/).
	Content string `json:"content"`

	// ID This id property is autogenerated when a task is created.
	ID int64 `json:"id"`
}

func TestRuntime_Canary(t *testing.T) {
	// test that it can make a simple request
	// and get the response for it.
	// defaults all the way down
	result := []task{
		{false, "task 1 content", 1},
		{false, "task 2 content", 2},
	}
	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		rw.Header().Add(httpkit.HeaderContentType, httpkit.JSONMime)
		rw.WriteHeader(http.StatusOK)
		jsongen := json.NewEncoder(rw)
		jsongen.Encode(result)
	}))

	rwrtr := client.RequestWriterFunc(func(req client.Request, _ strfmt.Registry) error {
		return nil
	})

	specDoc, err := spec.Load("../../fixtures/codegen/todolist.simple.yml")
	hu, _ := url.Parse(server.URL)
	specDoc.Spec().Host = hu.Host
	specDoc.Spec().BasePath = "/"
	if assert.NoError(t, err) {

		runtime := New(specDoc)
		res, err := runtime.Submit("getTasks", rwrtr, client.ResponseReaderFunc(func(response client.Response, consumer httpkit.Consumer) (interface{}, error) {
			if response.Code() == 200 {
				var result []task
				if err := consumer.Consume(response.Body(), &result); err != nil {
					return nil, err
				}
				return result, nil
			}
			return nil, errors.New("Generic error")
		}))

		if assert.NoError(t, err) {
			assert.IsType(t, []task{}, res)
			actual := res.([]task)
			assert.EqualValues(t, result, actual)
		}
	}
}
<commit_msg>fix test compilation<commit_after>package client

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/go-swagger/go-swagger/client"
	"github.com/go-swagger/go-swagger/httpkit"
	"github.com/go-swagger/go-swagger/spec"
	"github.com/go-swagger/go-swagger/strfmt"
	"github.com/stretchr/testify/assert"
)

// task This describes a task. Tasks require a content property to be set.
type task struct {

	// Completed
	Completed bool `json:"completed"`

	// Content Task content can contain [GFM](https://help.github.com/articles/github-flavored-markdown/).
	Content string `json:"content"`

	// ID This id property is autogenerated when a task is created.
	ID int64 `json:"id"`
}

func TestRuntime_Canary(t *testing.T) {
	// test that it can make a simple request
	// and get the response for it.
	// defaults all the way down
	result := []task{
		{false, "task 1 content", 1},
		{false, "task 2 content", 2},
	}
	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		rw.Header().Add(httpkit.HeaderContentType, httpkit.JSONMime)
		rw.WriteHeader(http.StatusOK)
		jsongen := json.NewEncoder(rw)
		jsongen.Encode(result)
	}))

	rwrtr := client.RequestWriterFunc(func(req client.Request, _ strfmt.Registry) error {
		return nil
	})

	specDoc, err := spec.Load("../../fixtures/codegen/todolist.simple.yml")
	hu, _ := url.Parse(server.URL)
	specDoc.Spec().Host = hu.Host
	specDoc.Spec().BasePath = "/"
	if assert.NoError(t, err) {

		runtime := New(specDoc)
		res, err := runtime.Submit(&client.Operation{
			ID:     "getTasks",
			Params: rwrtr,
			Reader: client.ResponseReaderFunc(func(response client.Response, consumer httpkit.Consumer) (interface{}, error) {
				if response.Code() == 200 {
					var result []task
					if err := consumer.Consume(response.Body(), &result); err != nil {
						return nil, err
					}
					return result, nil
				}
				return nil, errors.New("Generic error")
			}),
		})

		if assert.NoError(t, err) {
			assert.IsType(t, []task{}, res)
			actual := res.([]task)
			assert.EqualValues(t, result, actual)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google, Inc. All rights reserved.

package layers

import (
	"github.com/gconnell/gopacket"
)

// FDDI contains the header for FDDI frames.
type FDDI struct {
	baseLayer
	FrameControl   FDDIFrameControl
	Priority       uint8
	SrcMAC, DstMac []byte
}

func (f *FDDI) LayerType() gopacket.LayerType { return LayerTypeFDDI }

func decodeFDDI(data []byte, p gopacket.PacketBuilder) error {
	f := &FDDI{
		FrameControl: FDDIFrameControl(data[0] & 0xF8),
		Priority:     data[0] & 0x07,
		SrcMAC:       data[1:7],
		DstMac:       data[7:13],
		baseLayer:    baseLayer{data[:13], data[13:]},
	}
	p.AddLayer(f)
	return p.NextDecoder(f.FrameControl)
}
<commit_msg>Make FDDI a link layer.<commit_after>// Copyright 2012 Google, Inc. All rights reserved.

package layers

import (
	"github.com/gconnell/gopacket"
)

// FDDI contains the header for FDDI frames.
type FDDI struct {
	baseLayer
	FrameControl   FDDIFrameControl
	Priority       uint8
	SrcMAC, DstMAC []byte
}

func (f *FDDI) LayerType() gopacket.LayerType { return LayerTypeFDDI }

func (f *FDDI) LinkFlow() gopacket.Flow {
	return gopacket.NewFlow(EndpointMAC, f.SrcMAC, f.DstMAC)
}

func decodeFDDI(data []byte, p gopacket.PacketBuilder) error {
	f := &FDDI{
		FrameControl: FDDIFrameControl(data[0] & 0xF8),
		Priority:     data[0] & 0x07,
		SrcMAC:       data[1:7],
		DstMAC:       data[7:13],
		baseLayer:    baseLayer{data[:13], data[13:]},
	}
	p.SetLinkLayer(f)
	p.AddLayer(f)
	return p.NextDecoder(f.FrameControl)
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

package layers

import (
	"encoding/binary"
	"fmt"

	"github.com/google/gopacket"
)

type OSPFType uint8

// Potential values for OSPF.Type.
const (
	OSPFHello                   OSPFType = 1
	OSPFDatabaseDescription     OSPFType = 2
	OSPFLinkStateRequest        OSPFType = 3
	OSPFLinkStateUpdate         OSPFType = 4
	OSPFLinkStateAcknowledgment OSPFType = 5
)

func (i OSPFType) String() string {
	switch i {
	case OSPFHello:
		return "Hello"
	case OSPFDatabaseDescription:
		return "Database Description"
	case OSPFLinkStateRequest:
		return "Link State Request"
	case OSPFLinkStateUpdate:
		return "Link State Update"
	case OSPFLinkStateAcknowledgment:
		return "Link State Acknowledgment"
	default:
		return ""
	}
}

//OSPFv2 extend the OSPF head with version 2 specific fields
type OSPFv2 struct {
	AuType         uint16
	Authentication uint64
}

// OSPFv3 extend the OSPF head with version 3 specific fields
type OSPFv3 struct {
	Instance uint8
	Reserved uint8
}

// OSPF is a basic OSPF packet header with common fields of Version 2 and Version 3.
type OSPF struct {
	BaseLayer
	OSPFv2
	OSPFv3
	Version      uint8
	Type         OSPFType
	PacketLength uint16
	RouterID     uint32
	AreaID       uint32
	Checksum     uint16
}

func (ospf *OSPF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 14 {
		return fmt.Errorf("Packet too smal for OSPF")
	}

	ospf.Version = uint8(data[0])
	ospf.Type = OSPFType(data[1])
	ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
	ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
	ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
	ospf.Checksum = binary.BigEndian.Uint16(data[12:14])

	switch ospf.Version {
	case 2:
		if len(data) < 24 {
			return fmt.Errorf("Packet too smal for OSPF Version 2")
		}
		ospf.AuType = binary.BigEndian.Uint16(data[14:16])
		ospf.Authentication = binary.BigEndian.Uint64(data[16:24])
	case 3:
		if len(data) < 16 {
			return fmt.Errorf("Packet too smal for OSPF Version 3")
		}
		ospf.Instance = uint8(data[14])
		ospf.Reserved = uint8(data[15])
	default:
		return fmt.Errorf("Unsupported OSPF version")
	}

	return nil
}

// LayerType returns LayerTypeOSPF
func (ospf *OSPF) LayerType() gopacket.LayerType {
	return LayerTypeOSPF
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (ospf *OSPF) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypePayload
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (ospf *OSPF) CanDecode() gopacket.LayerClass {
	return LayerTypeOSPF
}

func decodeOSPF(data []byte, p gopacket.PacketBuilder) error {

	ospf := &OSPF{}
	return decodingLayerDecoder(ospf, data, p)
}
<commit_msg>Add missing comments<commit_after>// Copyright 2017 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.

package layers

import (
	"encoding/binary"
	"fmt"

	"github.com/google/gopacket"
)

// OSPFType denotes what kind of OSPF type it is
type OSPFType uint8

// Potential values for OSPF.Type.
const (
	OSPFHello                   OSPFType = 1
	OSPFDatabaseDescription     OSPFType = 2
	OSPFLinkStateRequest        OSPFType = 3
	OSPFLinkStateUpdate         OSPFType = 4
	OSPFLinkStateAcknowledgment OSPFType = 5
)

// String conversions for OSPFType
func (i OSPFType) String() string {
	switch i {
	case OSPFHello:
		return "Hello"
	case OSPFDatabaseDescription:
		return "Database Description"
	case OSPFLinkStateRequest:
		return "Link State Request"
	case OSPFLinkStateUpdate:
		return "Link State Update"
	case OSPFLinkStateAcknowledgment:
		return "Link State Acknowledgment"
	default:
		return ""
	}
}

//OSPFv2 extend the OSPF head with version 2 specific fields
type OSPFv2 struct {
	AuType         uint16
	Authentication uint64
}

// OSPFv3 extend the OSPF head with version 3 specific fields
type OSPFv3 struct {
	Instance uint8
	Reserved uint8
}

// OSPF is a basic OSPF packet header with common fields of Version 2 and Version 3.
type OSPF struct {
	BaseLayer
	OSPFv2
	OSPFv3
	Version      uint8
	Type         OSPFType
	PacketLength uint16
	RouterID     uint32
	AreaID       uint32
	Checksum     uint16
}

// DecodeFromBytes decodes the given bytes into the OSPF layer.
func (ospf *OSPF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 14 {
		return fmt.Errorf("Packet too smal for OSPF")
	}

	ospf.Version = uint8(data[0])
	ospf.Type = OSPFType(data[1])
	ospf.PacketLength = binary.BigEndian.Uint16(data[2:4])
	ospf.RouterID = binary.BigEndian.Uint32(data[4:8])
	ospf.AreaID = binary.BigEndian.Uint32(data[8:12])
	ospf.Checksum = binary.BigEndian.Uint16(data[12:14])

	switch ospf.Version {
	case 2:
		if len(data) < 24 {
			return fmt.Errorf("Packet too smal for OSPF Version 2")
		}
		ospf.AuType = binary.BigEndian.Uint16(data[14:16])
		ospf.Authentication = binary.BigEndian.Uint64(data[16:24])
	case 3:
		if len(data) < 16 {
			return fmt.Errorf("Packet too smal for OSPF Version 3")
		}
		ospf.Instance = uint8(data[14])
		ospf.Reserved = uint8(data[15])
	default:
		return fmt.Errorf("Unsupported OSPF version")
	}

	return nil
}

// LayerType returns LayerTypeOSPF
func (ospf *OSPF) LayerType() gopacket.LayerType {
	return LayerTypeOSPF
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (ospf *OSPF) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypePayload
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (ospf *OSPF) CanDecode() gopacket.LayerClass {
	return LayerTypeOSPF
}

func decodeOSPF(data []byte, p gopacket.PacketBuilder) error {

	ospf := &OSPF{}
	return decodingLayerDecoder(ospf, data, p)
}
<|endoftext|>


<commit_before>package auth

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import (
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"golang.org/x/crypto/scrypt"
)

// SCRYPTComponents the input parameters to the Scrypt encryption key format
type SCRYPTComponents struct {
	Algorithm string // The SCRYPT algorithm prefix
	N         int    // CPU/memory cost parameter (logN)
	R         int    // block size parameter (octets)
	P         int    // parallelisation parameter (positive int)
	Salt      []byte // salt value
	SaltLen   int    // bytes to use as salt (octets)
	DK        []byte // derived key value
	DKLen     int    // length of the derived key (octets)
}

const KEY_DELIM = ":"

var DefaultParams = SCRYPTComponents{
	Algorithm: "SCRYPT",
	N:         16384,
	R:         8,
	P:         1,
	SaltLen:   16,
	DKLen:     64}

// DerivePassword uses the golang.org/x/crypto package to
// return an encrypted password that is compatible with the
// Perl CPAN library Crypt::ScryptKDF for backward compatibility
// to authenticate through the Perl API the same way.
// See: http://cpansearch.perl.org/src/MIK/Crypt-ScryptKDF-0.010/lib/Crypt/ScryptKDF.pm
func DerivePassword(password string) (string, error) {
	var salt []byte
	var err error
	salt, err = generateSalt(64)
	if err != nil {
		return "", err
	}
	key, err := scrypt.Key([]byte(password), salt, DefaultParams.N, DefaultParams.R, DefaultParams.P, DefaultParams.DKLen)
	if err != nil {
		return "", err
	}
	nStr := strconv.Itoa(DefaultParams.N)
	if err != nil {
		return "", err
	}
	rStr := strconv.Itoa(DefaultParams.R)
	pStr := strconv.Itoa(DefaultParams.P)
	saltBase64 := base64.StdEncoding.EncodeToString(salt)
	keyBase64 := base64.StdEncoding.EncodeToString(key)

	// The SCRYPT prefix is added because the Mojolicious Perl library adds this as a prefix to every password in the database.  So it's added for compatibility.
	return DefaultParams.Algorithm +
		KEY_DELIM +
		nStr +
		KEY_DELIM +
		rStr +
		KEY_DELIM +
		pStr +
		KEY_DELIM +
		saltBase64 +
		KEY_DELIM +
		keyBase64, nil
}

// VerifyPassword parses the original Derived Key (DK) from the SCRYPT password
// so that it can compare that with the password/scriptPassword param
func VerifyPassword(password string, scryptPassword string) error {

	scomp, err := parseScrypt(scryptPassword)
	if err != nil {
		return err
	}

	keylenBytes := len(scryptPassword) - DefaultParams.DKLen
	if keylenBytes < 1 {
		return errors.New("Invalid targetKey length")
	}
	// scrypt the cleartext password with the same parameters and salt
	tmpDK, err := scrypt.Key([]byte(password),
		[]byte(scomp.Salt),
		scomp.N, // Must be a power of 2 greater than 1
		scomp.R,
		scomp.P, // r*p must be < 2^30
		DefaultParams.DKLen)
	if err != nil {
		return err
	}
	// Compare the Derived Key from the SCRYPT password
	if subtle.ConstantTimeCompare(scomp.DK, tmpDK) == 1 {
		return nil
	}

	return err
}

func parseScrypt(scryptPassword string) (SCRYPTComponents, error) {
	sh := strings.Split(scryptPassword, ":")

	var err error
	var scomp SCRYPTComponents
	if scryptPassword == "" {
		return scomp, errors.New("scrypt password is required")
	}

	// Algorithm
	scomp.Algorithm = sh[0]
	if scomp.Algorithm == "" {
		return scomp, errors.New("Algorithm was not defined")
	}

	// N
	n := sh[1]
	if n == "" {
		return scomp, errors.New("N was not defined")
	}
	var nInt int
	nInt, err = strconv.Atoi(n)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("%v i=%d, type: %T\n", err, nInt, nInt))
	}
	scomp.N = nInt

	// R
	r := sh[2]
	if r == "" {
		return scomp, errors.New("r was not defined")
	}

	scomp.R, err = strconv.Atoi(r)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("i=%d, type: %T\n", scomp.R, scomp.R))
	}

	// P
	p := sh[3]
	if p == "" {
		return scomp, errors.New("p was not defined")
	}
	scomp.P, err = strconv.Atoi(p)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("i=%d, type: %T\n", scomp.P, scomp.P))
	}

	// Salt
	saltBase64 := sh[4]

	scomp.Salt, err = base64.StdEncoding.DecodeString(saltBase64)
	if err != nil {
		return scomp, errors.New("salt cannot be decoded")
	}
	scomp.SaltLen = len(scomp.Salt)
	if len(scomp.Salt) < 0 {
		return scomp, errors.New("salt length is less than zero")
	}

	// Salt
	dkBase64 := sh[5]
	scomp.DK, err = base64.StdEncoding.DecodeString(dkBase64)
	if err != nil {
		return scomp, errors.New("key cannot be decoded")
	}
	return scomp, err
}

// generateSalt returns securely generated random bytes.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func generateSalt(n int) ([]byte, error) {
	b := make([]byte, n)
	_, err := rand.Read(b)
	// Note that err == nil only if we read len(b) bytes.
	if err != nil {
		return nil, err
	}

	return b, nil
}
<commit_msg>americanized parallelization<commit_after>package auth

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import (
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"golang.org/x/crypto/scrypt"
)

// SCRYPTComponents the input parameters to the Scrypt encryption key format
type SCRYPTComponents struct {
	Algorithm string // The SCRYPT algorithm prefix
	N         int    // CPU/memory cost parameter (logN)
	R         int    // block size parameter (octets)
	P         int    // parallelization parameter (positive int)
	Salt      []byte // salt value
	SaltLen   int    // bytes to use as salt (octets)
	DK        []byte // derived key value
	DKLen     int    // length of the derived key (octets)
}

const KEY_DELIM = ":"

var DefaultParams = SCRYPTComponents{
	Algorithm: "SCRYPT",
	N:         16384,
	R:         8,
	P:         1,
	SaltLen:   16,
	DKLen:     64}

// DerivePassword uses the golang.org/x/crypto package to
// return an encrypted password that is compatible with the
// Perl CPAN library Crypt::ScryptKDF for backward compatibility
// to authenticate through the Perl API the same way.
// See: http://cpansearch.perl.org/src/MIK/Crypt-ScryptKDF-0.010/lib/Crypt/ScryptKDF.pm
func DerivePassword(password string) (string, error) {
	var salt []byte
	var err error
	salt, err = generateSalt(64)
	if err != nil {
		return "", err
	}
	key, err := scrypt.Key([]byte(password), salt, DefaultParams.N, DefaultParams.R, DefaultParams.P, DefaultParams.DKLen)
	if err != nil {
		return "", err
	}
	nStr := strconv.Itoa(DefaultParams.N)
	if err != nil {
		return "", err
	}
	rStr := strconv.Itoa(DefaultParams.R)
	pStr := strconv.Itoa(DefaultParams.P)
	saltBase64 := base64.StdEncoding.EncodeToString(salt)
	keyBase64 := base64.StdEncoding.EncodeToString(key)

	// The SCRYPT prefix is added because the Mojolicious Perl library adds this as a prefix to every password in the database.  So it's added for compatibility.
	return DefaultParams.Algorithm +
		KEY_DELIM +
		nStr +
		KEY_DELIM +
		rStr +
		KEY_DELIM +
		pStr +
		KEY_DELIM +
		saltBase64 +
		KEY_DELIM +
		keyBase64, nil
}

// VerifyPassword parses the original Derived Key (DK) from the SCRYPT password
// so that it can compare that with the password/scriptPassword param
func VerifyPassword(password string, scryptPassword string) error {

	scomp, err := parseScrypt(scryptPassword)
	if err != nil {
		return err
	}

	keylenBytes := len(scryptPassword) - DefaultParams.DKLen
	if keylenBytes < 1 {
		return errors.New("Invalid targetKey length")
	}
	// scrypt the cleartext password with the same parameters and salt
	tmpDK, err := scrypt.Key([]byte(password),
		[]byte(scomp.Salt),
		scomp.N, // Must be a power of 2 greater than 1
		scomp.R,
		scomp.P, // r*p must be < 2^30
		DefaultParams.DKLen)
	if err != nil {
		return err
	}
	// Compare the Derived Key from the SCRYPT password
	if subtle.ConstantTimeCompare(scomp.DK, tmpDK) == 1 {
		return nil
	}

	return err
}

func parseScrypt(scryptPassword string) (SCRYPTComponents, error) {
	sh := strings.Split(scryptPassword, ":")

	var err error
	var scomp SCRYPTComponents
	if scryptPassword == "" {
		return scomp, errors.New("scrypt password is required")
	}

	// Algorithm
	scomp.Algorithm = sh[0]
	if scomp.Algorithm == "" {
		return scomp, errors.New("Algorithm was not defined")
	}

	// N
	n := sh[1]
	if n == "" {
		return scomp, errors.New("N was not defined")
	}
	var nInt int
	nInt, err = strconv.Atoi(n)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("%v i=%d, type: %T\n", err, nInt, nInt))
	}
	scomp.N = nInt

	// R
	r := sh[2]
	if r == "" {
		return scomp, errors.New("r was not defined")
	}

	scomp.R, err = strconv.Atoi(r)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("i=%d, type: %T\n", scomp.R, scomp.R))
	}

	// P
	p := sh[3]
	if p == "" {
		return scomp, errors.New("p was not defined")
	}
	scomp.P, err = strconv.Atoi(p)
	if err != nil {
		return scomp, errors.New(fmt.Sprintf("i=%d, type: %T\n", scomp.P, scomp.P))
	}

	// Salt
	saltBase64 := sh[4]

	scomp.Salt, err = base64.StdEncoding.DecodeString(saltBase64)
	if err != nil {
		return scomp, errors.New("salt cannot be decoded")
	}
	scomp.SaltLen = len(scomp.Salt)
	if len(scomp.Salt) < 0 {
		return scomp, errors.New("salt length is less than zero")
	}

	// Salt
	dkBase64 := sh[5]
	scomp.DK, err = base64.StdEncoding.DecodeString(dkBase64)
	if err != nil {
		return scomp, errors.New("key cannot be decoded")
	}
	return scomp, err
}

// generateSalt returns securely generated random bytes.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func generateSalt(n int) ([]byte, error) {
	b := make([]byte, n)
	_, err := rand.Read(b)
	// Note that err == nil only if we read len(b) bytes.
	if err != nil {
		return nil, err
	}

	return b, nil
}
<|endoftext|>


<commit_before>/* Copyright (C) 2015-2020 김운하 (unha.kim@ghts.org)

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (unha.kim@ghts.org)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>. */

package x32

import (
	"github.com/ghts/ghts/lib"
	"github.com/ghts/ghts/lib/nanomsg"
	xt "github.com/ghts/ghts/xing/base"
	"testing"
)

func TestP접속됨(t *testing.T) {
	t.Parallel()

	if !lib.F인터넷에_접속됨() {
		t.SkipNow()
	}

	소켓REQ, 에러 := nano.NewNano소켓REQ(xt.F주소_C32_호출(), lib.P10초)
	lib.F테스트_에러없음(t, 에러)

	defer 소켓REQ.Close()

	질의값 := lib.New질의값_기본형(lib.TR접속됨, "")

	응답 := 소켓REQ.G질의_응답_검사(lib.P변환형식_기본값, 질의값)
	lib.F테스트_에러없음(t, 응답.G에러())
	lib.F테스트_같음(t, 응답.G수량(), 1)

	접속됨, 에러 := f접속됨()
	lib.F테스트_에러없음(t, 에러)

	참거짓, ok := 응답.G해석값_단순형(0).(bool)
	lib.F테스트_참임(t, ok)
	lib.F테스트_같음(t, 참거짓, 접속됨)
}
<commit_msg>오타 수정<commit_after>/* Copyright (C) 2015-2020 김운하 (unha.kim@ghts.org)

이 파일은 GHTS의 일부입니다.

이 프로그램은 자유 소프트웨어입니다.
소프트웨어의 피양도자는 자유 소프트웨어 재단이 공표한 GNU LGPL 2.1판
규정에 따라 프로그램을 개작하거나 재배포할 수 있습니다.

이 프로그램은 유용하게 사용될 수 있으리라는 희망에서 배포되고 있지만,
특정한 목적에 적합하다거나, 이익을 안겨줄 수 있다는 묵시적인 보증을 포함한
어떠한 형태의 보증도 제공하지 않습니다.
보다 자세한 사항에 대해서는 GNU LGPL 2.1판을 참고하시기 바랍니다.
GNU LGPL 2.1판은 이 프로그램과 함께 제공됩니다.
만약, 이 문서가 누락되어 있다면 자유 소프트웨어 재단으로 문의하시기 바랍니다.
(자유 소프트웨어 재단 : Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA)

Copyright (C) 2015-2020년 UnHa Kim (unha.kim@ghts.org)

This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, version 2.1 of the License.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>. */

package x32

import (
	"github.com/ghts/ghts/lib"
	"github.com/ghts/ghts/lib/nanomsg"
	xt "github.com/ghts/ghts/xing/base"
	"testing"
)

func TestF접속됨(t *testing.T) {
	t.Parallel()

	if !lib.F인터넷에_접속됨() {
		t.SkipNow()
	}

	소켓REQ, 에러 := nano.NewNano소켓REQ(xt.F주소_C32_호출(), lib.P10초)
	lib.F테스트_에러없음(t, 에러)

	defer 소켓REQ.Close()

	질의값 := lib.New질의값_기본형(lib.TR접속됨, "")

	응답 := 소켓REQ.G질의_응답_검사(lib.P변환형식_기본값, 질의값)
	lib.F테스트_에러없음(t, 응답.G에러())
	lib.F테스트_같음(t, 응답.G수량(), 1)

	접속됨, 에러 := f접속됨()
	lib.F테스트_에러없음(t, 에러)

	참거짓, ok := 응답.G해석값_단순형(0).(bool)
	lib.F테스트_참임(t, ok)
	lib.F테스트_같음(t, 참거짓, 접속됨)
}
<|endoftext|>


<commit_before>package models

import (
	"time"

	"errors"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

//Interval contains the Duration of a work from a user
type Interval struct {
	ID     bson.ObjectId `bson:"_id,omitempty"`
	UserID bson.ObjectId
	Start  time.Time
	Stop   time.Time `bson:",omitempty"`
}

type IntervalDao struct {
	dbName         string
	collectionName string
	session        *mgo.Session
}

func NewInterval(userID bson.ObjectId, start time.Time, stop time.Time) Interval {
	return Interval{UserID: userID, Start: start, Stop: stop}
}

func NewIntervalWithStart(userID bson.ObjectId, start time.Time) Interval {
	return Interval{UserID: userID, Start: start}
}

func NewPersistedInterval(id bson.ObjectId, userID bson.ObjectId, start time.Time, stop time.Time) Interval {
	return Interval{id, userID, start, stop}
}

func NewPersistedIntervalWithStart(userID bson.ObjectId, start time.Time) Interval {
	return Interval{UserID: userID, Start: start}
}

func NewIntervalDao(session *mgo.Session, dbName string) *IntervalDao {
	return &IntervalDao{session: session, dbName: dbName, collectionName: "intervals"}
}

func (dao *IntervalDao) Save(interval Interval) error {
	return dao.getDBCollection().Insert(interval)
}

func (dao *IntervalDao) FindByUserID(userID bson.ObjectId) ([]Interval, error) {
	var intervals []Interval
	err := dao.getDBCollection().Find(bson.M{"userid": userID}).All(&intervals)
	return intervals, err
}

func (dao *IntervalDao) IsUserWorking(userID bson.ObjectId) (bool, error) {
	query := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	openIntervals, err := dao.getDBCollection().Find(query).Count()
	working := openIntervals > 0
	return working, err
}

func (dao *IntervalDao) Start(userID bson.ObjectId) error {
	return dao.Save(NewIntervalWithStart(userID, time.Now()))
}

func (dao *IntervalDao) Stop(userID bson.ObjectId) error {
	openIntervals, err := dao.FindOpenIntervals(userID)
	if validationErr := checkStopErrors(openIntervals, err); validationErr != nil {
		return validationErr
	}
	query := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	change := bson.M{"$set": bson.M{"stop": time.Now()}}
	return dao.getDBCollection().Update(query, change)
}

func checkStopErrors(openIntervals []Interval, err error) error {
	if err != nil {
		return err
	}
	if len(openIntervals) > 1 {
		return errors.New("more than one open interval")
	}
	if len(openIntervals) == 0 {
		return errors.New("user is not working")
	}
	return nil
}

func (dao *IntervalDao) FindOpenIntervals(userID bson.ObjectId) ([]Interval, error) {
	var openIntervals []Interval
	findQuery := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	err := dao.getDBCollection().Find(findQuery).All(&openIntervals)
	return openIntervals, err
}

func (dao *IntervalDao) getDBConnection() *mgo.Database {
	return dao.session.Clone().DB(dao.dbName)
}

func (dao *IntervalDao) getDBCollection() *mgo.Collection {
	return dao.getDBConnection().C(dao.collectionName)
}
<commit_msg>test wether its a problem with updateID method<commit_after>package models

import (
	"time"

	"errors"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

//Interval contains the Duration of a work from a user
type Interval struct {
	ID     bson.ObjectId `bson:"_id,omitempty"`
	UserID bson.ObjectId
	Start  time.Time
	Stop   time.Time `bson:",omitempty"`
}

type IntervalDao struct {
	dbName         string
	collectionName string
	session        *mgo.Session
}

func NewInterval(userID bson.ObjectId, start time.Time, stop time.Time) Interval {
	return Interval{UserID: userID, Start: start, Stop: stop}
}

func NewIntervalWithStart(userID bson.ObjectId, start time.Time) Interval {
	return Interval{UserID: userID, Start: start}
}

func NewPersistedInterval(id bson.ObjectId, userID bson.ObjectId, start time.Time, stop time.Time) Interval {
	return Interval{id, userID, start, stop}
}

func NewPersistedIntervalWithStart(userID bson.ObjectId, start time.Time) Interval {
	return Interval{UserID: userID, Start: start}
}

func NewIntervalDao(session *mgo.Session, dbName string) *IntervalDao {
	return &IntervalDao{session: session, dbName: dbName, collectionName: "intervals"}
}

func (dao *IntervalDao) Save(interval Interval) error {
	return dao.getDBCollection().Insert(interval)
}

func (dao *IntervalDao) FindByUserID(userID bson.ObjectId) ([]Interval, error) {
	var intervals []Interval
	err := dao.getDBCollection().Find(bson.M{"userid": userID}).All(&intervals)
	return intervals, err
}

func (dao *IntervalDao) IsUserWorking(userID bson.ObjectId) (bool, error) {
	query := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	openIntervals, err := dao.getDBCollection().Find(query).Count()
	working := openIntervals > 0
	return working, err
}

func (dao *IntervalDao) Start(userID bson.ObjectId) error {
	return dao.Save(NewIntervalWithStart(userID, time.Now()))
}

func (dao *IntervalDao) Stop(userID bson.ObjectId) error {
	openIntervals, err := dao.FindOpenIntervals(userID)
	if validationErr := checkStopErrors(openIntervals, err); validationErr != nil {
		return validationErr
	}
	//	query := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	change := bson.M{"$set": bson.M{"stop": time.Now()}}
	return dao.getDBCollection().Update(bson.M{"_id": openIntervals[0].ID}, change)
}

func checkStopErrors(openIntervals []Interval, err error) error {
	if err != nil {
		return err
	}
	if len(openIntervals) > 1 {
		return errors.New("more than one open interval")
	}
	if len(openIntervals) == 0 {
		return errors.New("user is not working")
	}
	return nil
}

func (dao *IntervalDao) FindOpenIntervals(userID bson.ObjectId) ([]Interval, error) {
	var openIntervals []Interval
	findQuery := bson.M{"userid": userID, "stop": bson.M{"$exists": false}}
	err := dao.getDBCollection().Find(findQuery).All(&openIntervals)
	return openIntervals, err
}

func (dao *IntervalDao) getDBConnection() *mgo.Database {
	return dao.session.Clone().DB(dao.dbName)
}

func (dao *IntervalDao) getDBCollection() *mgo.Collection {
	return dao.getDBConnection().C(dao.collectionName)
}
<|endoftext|>


<commit_before>package cmdutil

import (
	"bytes"
	"io/ioutil"
	"os/exec"
	"strings"
)

// ExecSimple provides a simple interface to execute a system
// command.
func ExecSimple(command, stdoutFile, stderrFile string) (bytes.Buffer, bytes.Buffer, error) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	parts := strings.Split(command, " ")
	cmd := exec.Command(parts[0], parts[1:]...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		return stdout, stderr, err
	}
	stdoutFile = strings.TrimSpace(stdoutFile)
	stderrFile = strings.TrimSpace(stderrFile)
	if len(stdoutFile) > 0 {
		err := ioutil.WriteFile(stdoutFile, stdout.Bytes(), 0644)
		if err != nil {
			return stdout, stderr, err
		}
	}
	if len(stderrFile) > 0 {
		err := ioutil.WriteFile(stderrFile, stdout.Bytes(), 0644)
		if err != nil {
			return stdout, stderr, err
		}
	}
	return stdout, stderr, nil
}
<commit_msg>enhance: cmdutil.ExecSsimple write files<commit_after>package cmdutil

import (
	"bytes"
	"io/ioutil"
	"os/exec"
	"strings"
)

// ExecSimple provides a simple interface to execute a system command.
func ExecSimple(command, stdoutFile, stderrFile string) (bytes.Buffer, bytes.Buffer, error) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	parts := strings.Split(command, " ")
	cmd := exec.Command(parts[0], parts[1:]...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		return stdout, stderr, err
	}
	stdoutFile = strings.TrimSpace(stdoutFile)
	stderrFile = strings.TrimSpace(stderrFile)
	if len(stdoutFile) > 0 {
		err := ioutil.WriteFile(stdoutFile, stdout.Bytes(), 0644)
		if err != nil {
			return stdout, stderr, err
		}
	}
	if len(stderrFile) > 0 {
		err := ioutil.WriteFile(stderrFile, stdout.Bytes(), 0644)
		if err != nil {
			return stdout, stderr, err
		}
	}
	return stdout, stderr, nil
}
<|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 compose

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	dockercli "github.com/docker/cli/cli"
	"github.com/docker/cli/cli-plugins/manager"
	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/morikuni/aec"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/docker/compose/v2/pkg/api"
	"github.com/docker/compose/v2/pkg/compose"
)

// Command defines a compose CLI command as a func with args
type Command func(context.Context, []string) error

// CobraCommand defines a cobra command function
type CobraCommand func(context.Context, *cobra.Command, []string) error

// AdaptCmd adapt a CobraCommand func to cobra library
func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
	return func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		contextString := fmt.Sprintf("%s", ctx)
		if !strings.HasSuffix(contextString, ".WithCancel") { // need to handle cancel
			cancellableCtx, cancel := context.WithCancel(cmd.Context())
			ctx = cancellableCtx
			s := make(chan os.Signal, 1)
			signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
			go func() {
				<-s
				cancel()
			}()
		}
		err := fn(ctx, cmd, args)
		var composeErr compose.Error
		if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
			err = dockercli.StatusError{
				StatusCode: 130,
				Status:     compose.CanceledStatus,
			}
		}
		if errors.As(err, &composeErr) {
			err = dockercli.StatusError{
				StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
				Status:     err.Error(),
			}
		}
		return err
	}
}

// Adapt a Command func to cobra library
func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
	return AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
		return fn(ctx, args)
	})
}

// Warning is a global warning to be displayed to user on command failure
var Warning string

type projectOptions struct {
	ProjectName   string
	Profiles      []string
	ConfigPaths   []string
	WorkDir       string
	ProjectDir    string
	EnvFile       string
	Compatibility bool
}

// ProjectFunc does stuff within a types.Project
type ProjectFunc func(ctx context.Context, project *types.Project) error

// ProjectServicesFunc does stuff within a types.Project and a selection of services
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error

// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
	return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
		return fn(ctx, project)
	})
}

// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
	return Adapt(func(ctx context.Context, args []string) error {
		project, err := o.toProject(args, cli.WithResolvedPaths(true))
		if err != nil {
			return err
		}

		if o.EnvFile != "" {
			var services types.Services
			for _, s := range project.Services {
				ef := o.EnvFile
				if ef != "" {
					if !filepath.IsAbs(ef) {
						ef = filepath.Join(project.WorkingDir, o.EnvFile)
					}
					if s.Labels == nil {
						s.Labels = make(map[string]string)
					}
					s.Labels[api.EnvironmentFileLabel] = ef
					services = append(services, s)
				}
			}
			project.Services = services
		}

		return fn(ctx, project, args)
	})
}

func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
	f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
	f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
	f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
	f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.")
	f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the Compose file)")
	f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the Compose file)")
	f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
	_ = f.MarkHidden("workdir")
}

func (o *projectOptions) toProjectName() (string, error) {
	if o.ProjectName != "" {
		return o.ProjectName, nil
	}

	project, err := o.toProject(nil)
	if err != nil {
		return "", err
	}
	return project.Name, nil
}

func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
	options, err := o.toProjectOptions(po...)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	project, err := cli.ProjectFromOptions(options)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	if o.Compatibility || project.Environment["COMPOSE_COMPATIBILITY"] == "true" {
		compose.Separator = "_"
	}

	if len(services) > 0 {
		s, err := project.GetServices(services...)
		if err != nil {
			return nil, err
		}
		o.Profiles = append(o.Profiles, s.GetProfiles()...)
	}

	if profiles, ok := options.Environment["COMPOSE_PROFILES"]; ok {
		o.Profiles = append(o.Profiles, strings.Split(profiles, ",")...)
	}

	project.ApplyProfiles(o.Profiles)

	project.WithoutUnnecessaryResources()

	err = project.ForServices(services)
	return project, err
}

func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
	return cli.NewProjectOptions(o.ConfigPaths,
		append(po,
			cli.WithWorkingDirectory(o.ProjectDir),
			cli.WithEnvFile(o.EnvFile),
			cli.WithDotEnv,
			cli.WithOsEnv,
			cli.WithConfigFileEnv,
			cli.WithDefaultConfigPath,
			cli.WithName(o.ProjectName))...)
}

const PluginName = "compose"

// RunningAsStandalone detects when running as a standalone program
func RunningAsStandalone() bool {
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
}

// RootCommand returns the compose command with its child commands
func RootCommand(backend api.Service) *cobra.Command {
	opts := projectOptions{}
	var (
		ansi    string
		noAnsi  bool
		verbose bool
		version bool
	)
	command := &cobra.Command{
		Short:            "Docker Compose",
		Use:              PluginName,
		TraverseChildren: true,
		// By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) !
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return cmd.Help()
			}
			if version {
				return versionCommand().Execute()
			}
			_ = cmd.Help()
			return dockercli.StatusError{
				StatusCode: compose.CommandSyntaxFailure.ExitCode,
				Status:     fmt.Sprintf("unknown docker command: %q", "compose "+args[0]),
			}
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			parent := cmd.Root()
			if parent != nil {
				parentPrerun := parent.PersistentPreRunE
				if parentPrerun != nil {
					err := parentPrerun(cmd, args)
					if err != nil {
						return err
					}
				}
			}
			if noAnsi {
				if ansi != "auto" {
					return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
				}
				ansi = "never"
				fmt.Fprint(os.Stderr, aec.Apply("option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n", aec.RedF))
			}
			if verbose {
				logrus.SetLevel(logrus.TraceLevel)
			}
			formatter.SetANSIMode(ansi)
			if opts.WorkDir != "" {
				if opts.ProjectDir != "" {
					return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
				}
				opts.ProjectDir = opts.WorkDir
				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
			}
			return nil
		},
	}

	command.AddCommand(
		upCommand(&opts, backend),
		downCommand(&opts, backend),
		startCommand(&opts, backend),
		restartCommand(&opts, backend),
		stopCommand(&opts, backend),
		psCommand(&opts, backend),
		listCommand(backend),
		logsCommand(&opts, backend),
		convertCommand(&opts, backend),
		killCommand(&opts, backend),
		runCommand(&opts, backend),
		removeCommand(&opts, backend),
		execCommand(&opts, backend),
		pauseCommand(&opts, backend),
		unpauseCommand(&opts, backend),
		topCommand(&opts, backend),
		eventsCommand(&opts, backend),
		portCommand(&opts, backend),
		imagesCommand(&opts, backend),
		versionCommand(),
		buildCommand(&opts, backend),
		pushCommand(&opts, backend),
		pullCommand(&opts, backend),
		createCommand(&opts, backend),
		copyCommand(&opts, backend),
	)
	command.Flags().SetInterspersed(false)
	opts.addProjectFlags(command.Flags())
	command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
	command.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
	command.Flags().MarkHidden("version") //nolint:errcheck
	command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
	command.Flags().MarkHidden("no-ansi") //nolint:errcheck
	command.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
	command.Flags().MarkHidden("verbose") //nolint:errcheck
	return command
}
<commit_msg>Fix lint error<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 compose

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	dockercli "github.com/docker/cli/cli"
	"github.com/docker/cli/cli-plugins/manager"
	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/morikuni/aec"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/docker/compose/v2/pkg/api"
	"github.com/docker/compose/v2/pkg/compose"
)

// Command defines a compose CLI command as a func with args
type Command func(context.Context, []string) error

// CobraCommand defines a cobra command function
type CobraCommand func(context.Context, *cobra.Command, []string) error

// AdaptCmd adapt a CobraCommand func to cobra library
func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
	return func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		contextString := fmt.Sprintf("%s", ctx)
		if !strings.HasSuffix(contextString, ".WithCancel") { // need to handle cancel
			cancellableCtx, cancel := context.WithCancel(cmd.Context())
			ctx = cancellableCtx
			s := make(chan os.Signal, 1)
			signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
			go func() {
				<-s
				cancel()
			}()
		}
		err := fn(ctx, cmd, args)
		var composeErr compose.Error
		if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
			err = dockercli.StatusError{
				StatusCode: 130,
				Status:     compose.CanceledStatus,
			}
		}
		if errors.As(err, &composeErr) {
			err = dockercli.StatusError{
				StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
				Status:     err.Error(),
			}
		}
		return err
	}
}

// Adapt a Command func to cobra library
func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
	return AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
		return fn(ctx, args)
	})
}

// Warning is a global warning to be displayed to user on command failure
var Warning string

type projectOptions struct {
	ProjectName   string
	Profiles      []string
	ConfigPaths   []string
	WorkDir       string
	ProjectDir    string
	EnvFile       string
	Compatibility bool
}

// ProjectFunc does stuff within a types.Project
type ProjectFunc func(ctx context.Context, project *types.Project) error

// ProjectServicesFunc does stuff within a types.Project and a selection of services
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error

// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
	return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
		return fn(ctx, project)
	})
}

// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
	return Adapt(func(ctx context.Context, args []string) error {
		project, err := o.toProject(args, cli.WithResolvedPaths(true))
		if err != nil {
			return err
		}

		if o.EnvFile != "" {
			var services types.Services
			for _, s := range project.Services {
				ef := o.EnvFile
				if ef != "" {
					if !filepath.IsAbs(ef) {
						ef = filepath.Join(project.WorkingDir, o.EnvFile)
					}
					if s.Labels == nil {
						s.Labels = make(map[string]string)
					}
					s.Labels[api.EnvironmentFileLabel] = ef
					services = append(services, s)
				}
			}
			project.Services = services
		}

		return fn(ctx, project, args)
	})
}

func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
	f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
	f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
	f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
	f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.")
	f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the Compose file)")
	f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the Compose file)")
	f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
	_ = f.MarkHidden("workdir")
}

func (o *projectOptions) toProjectName() (string, error) {
	if o.ProjectName != "" {
		return o.ProjectName, nil
	}

	project, err := o.toProject(nil)
	if err != nil {
		return "", err
	}
	return project.Name, nil
}

func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
	options, err := o.toProjectOptions(po...)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	project, err := cli.ProjectFromOptions(options)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	if o.Compatibility || project.Environment["COMPOSE_COMPATIBILITY"] == "true" {
		compose.Separator = "_"
	}

	if len(services) > 0 {
		s, err := project.GetServices(services...)
		if err != nil {
			return nil, err
		}
		o.Profiles = append(o.Profiles, s.GetProfiles()...)
	}

	if profiles, ok := options.Environment["COMPOSE_PROFILES"]; ok {
		o.Profiles = append(o.Profiles, strings.Split(profiles, ",")...)
	}

	project.ApplyProfiles(o.Profiles)

	project.WithoutUnnecessaryResources()

	err = project.ForServices(services)
	return project, err
}

func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
	return cli.NewProjectOptions(o.ConfigPaths,
		append(po,
			cli.WithWorkingDirectory(o.ProjectDir),
			cli.WithEnvFile(o.EnvFile),
			cli.WithDotEnv,
			cli.WithOsEnv,
			cli.WithConfigFileEnv,
			cli.WithDefaultConfigPath,
			cli.WithName(o.ProjectName))...)
}

// PluginName is the name of the plugin
const PluginName = "compose"

// RunningAsStandalone detects when running as a standalone program
func RunningAsStandalone() bool {
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
}

// RootCommand returns the compose command with its child commands
func RootCommand(backend api.Service) *cobra.Command {
	opts := projectOptions{}
	var (
		ansi    string
		noAnsi  bool
		verbose bool
		version bool
	)
	command := &cobra.Command{
		Short:            "Docker Compose",
		Use:              PluginName,
		TraverseChildren: true,
		// By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) !
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return cmd.Help()
			}
			if version {
				return versionCommand().Execute()
			}
			_ = cmd.Help()
			return dockercli.StatusError{
				StatusCode: compose.CommandSyntaxFailure.ExitCode,
				Status:     fmt.Sprintf("unknown docker command: %q", "compose "+args[0]),
			}
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			parent := cmd.Root()
			if parent != nil {
				parentPrerun := parent.PersistentPreRunE
				if parentPrerun != nil {
					err := parentPrerun(cmd, args)
					if err != nil {
						return err
					}
				}
			}
			if noAnsi {
				if ansi != "auto" {
					return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
				}
				ansi = "never"
				fmt.Fprint(os.Stderr, aec.Apply("option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n", aec.RedF))
			}
			if verbose {
				logrus.SetLevel(logrus.TraceLevel)
			}
			formatter.SetANSIMode(ansi)
			if opts.WorkDir != "" {
				if opts.ProjectDir != "" {
					return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
				}
				opts.ProjectDir = opts.WorkDir
				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
			}
			return nil
		},
	}

	command.AddCommand(
		upCommand(&opts, backend),
		downCommand(&opts, backend),
		startCommand(&opts, backend),
		restartCommand(&opts, backend),
		stopCommand(&opts, backend),
		psCommand(&opts, backend),
		listCommand(backend),
		logsCommand(&opts, backend),
		convertCommand(&opts, backend),
		killCommand(&opts, backend),
		runCommand(&opts, backend),
		removeCommand(&opts, backend),
		execCommand(&opts, backend),
		pauseCommand(&opts, backend),
		unpauseCommand(&opts, backend),
		topCommand(&opts, backend),
		eventsCommand(&opts, backend),
		portCommand(&opts, backend),
		imagesCommand(&opts, backend),
		versionCommand(),
		buildCommand(&opts, backend),
		pushCommand(&opts, backend),
		pullCommand(&opts, backend),
		createCommand(&opts, backend),
		copyCommand(&opts, backend),
	)
	command.Flags().SetInterspersed(false)
	opts.addProjectFlags(command.Flags())
	command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
	command.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
	command.Flags().MarkHidden("version") //nolint:errcheck
	command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
	command.Flags().MarkHidden("no-ansi") //nolint:errcheck
	command.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
	command.Flags().MarkHidden("verbose") //nolint:errcheck
	return command
}
<|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 compose

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	dockercli "github.com/docker/cli/cli"
	"github.com/docker/cli/cli-plugins/manager"
	"github.com/docker/cli/cli/command"
	"github.com/morikuni/aec"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/docker/compose/v2/pkg/api"
	"github.com/docker/compose/v2/pkg/compose"
	"github.com/docker/compose/v2/pkg/progress"
	"github.com/docker/compose/v2/pkg/utils"
)

// Command defines a compose CLI command as a func with args
type Command func(context.Context, []string) error

// CobraCommand defines a cobra command function
type CobraCommand func(context.Context, *cobra.Command, []string) error

// AdaptCmd adapt a CobraCommand func to cobra library
func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
	return func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		contextString := fmt.Sprintf("%s", ctx)
		if !strings.HasSuffix(contextString, ".WithCancel") { // need to handle cancel
			cancellableCtx, cancel := context.WithCancel(cmd.Context())
			ctx = cancellableCtx
			s := make(chan os.Signal, 1)
			signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
			go func() {
				<-s
				cancel()
			}()
		}
		err := fn(ctx, cmd, args)
		var composeErr compose.Error
		if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
			err = dockercli.StatusError{
				StatusCode: 130,
				Status:     compose.CanceledStatus,
			}
		}
		if errors.As(err, &composeErr) {
			err = dockercli.StatusError{
				StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
				Status:     err.Error(),
			}
		}
		return err
	}
}

// Adapt a Command func to cobra library
func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
	return AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
		return fn(ctx, args)
	})
}

type projectOptions struct {
	ProjectName   string
	Profiles      []string
	ConfigPaths   []string
	WorkDir       string
	ProjectDir    string
	EnvFile       string
	Compatibility bool
}

// ProjectFunc does stuff within a types.Project
type ProjectFunc func(ctx context.Context, project *types.Project) error

// ProjectServicesFunc does stuff within a types.Project and a selection of services
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error

// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
	return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
		return fn(ctx, project)
	})
}

// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
	return Adapt(func(ctx context.Context, args []string) error {
		project, err := o.toProject(args, cli.WithResolvedPaths(true))
		if err != nil {
			return err
		}

		return fn(ctx, project, args)
	})
}

func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
	f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
	f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
	f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
	f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.")
	f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
	f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
	f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
	_ = f.MarkHidden("workdir")
}

func (o *projectOptions) toProjectName() (string, error) {
	if o.ProjectName != "" {
		return o.ProjectName, nil
	}

	envProjectName := os.Getenv("COMPOSE_PROJECT_NAME")
	if envProjectName != "" {
		return envProjectName, nil
	}

	project, err := o.toProject(nil)
	if err != nil {
		return "", err
	}
	return project.Name, nil
}

func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
	options, err := o.toProjectOptions(po...)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	project, err := cli.ProjectFromOptions(options)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	if o.Compatibility || utils.StringToBool(project.Environment["COMPOSE_COMPATIBILITY"]) {
		compose.Separator = "_"
	}

	ef := o.EnvFile
	if ef != "" && !filepath.IsAbs(ef) {
		ef, err = filepath.Abs(ef)
		if err != nil {
			return nil, err
		}
	}
	for i, s := range project.Services {
		s.CustomLabels = map[string]string{
			api.ProjectLabel:     project.Name,
			api.ServiceLabel:     s.Name,
			api.VersionLabel:     api.ComposeVersion,
			api.WorkingDirLabel:  project.WorkingDir,
			api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","),
			api.OneoffLabel:      "False", // default, will be overridden by `run` command
		}
		if ef != "" {
			s.CustomLabels[api.EnvironmentFileLabel] = ef
		}
		project.Services[i] = s
	}

	if len(services) > 0 {
		s, err := project.GetServices(services...)
		if err != nil {
			return nil, err
		}
		o.Profiles = append(o.Profiles, s.GetProfiles()...)
	}

	if profiles, ok := options.Environment["COMPOSE_PROFILES"]; ok {
		o.Profiles = append(o.Profiles, strings.Split(profiles, ",")...)
	}

	project.ApplyProfiles(o.Profiles)

	project.WithoutUnnecessaryResources()

	err = project.ForServices(services)
	return project, err
}

func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
	return cli.NewProjectOptions(o.ConfigPaths,
		append(po,
			cli.WithWorkingDirectory(o.ProjectDir),
			cli.WithEnvFile(o.EnvFile),
			cli.WithDotEnv,
			cli.WithOsEnv,
			cli.WithConfigFileEnv,
			cli.WithDefaultConfigPath,
			cli.WithName(o.ProjectName))...)
}

// PluginName is the name of the plugin
const PluginName = "compose"

// RunningAsStandalone detects when running as a standalone program
func RunningAsStandalone() bool {
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
}

// RootCommand returns the compose command with its child commands
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
	opts := projectOptions{}
	var (
		ansi    string
		noAnsi  bool
		verbose bool
		version bool
	)
	command := &cobra.Command{
		Short:            "Docker Compose",
		Use:              PluginName,
		TraverseChildren: true,
		// By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) !
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return cmd.Help()
			}
			if version {
				return versionCommand().Execute()
			}
			_ = cmd.Help()
			return dockercli.StatusError{
				StatusCode: compose.CommandSyntaxFailure.ExitCode,
				Status:     fmt.Sprintf("unknown docker command: %q", "compose "+args[0]),
			}
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			parent := cmd.Root()
			if parent != nil {
				parentPrerun := parent.PersistentPreRunE
				if parentPrerun != nil {
					err := parentPrerun(cmd, args)
					if err != nil {
						return err
					}
				}
			}
			if noAnsi {
				if ansi != "auto" {
					return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
				}
				ansi = "never"
				fmt.Fprint(os.Stderr, aec.Apply("option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n", aec.RedF))
			}
			if verbose {
				logrus.SetLevel(logrus.TraceLevel)
			}
			formatter.SetANSIMode(ansi)
			switch ansi {
			case "never":
				progress.Mode = progress.ModePlain
			case "tty":
				progress.Mode = progress.ModeTTY
			}
			if opts.WorkDir != "" {
				if opts.ProjectDir != "" {
					return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
				}
				opts.ProjectDir = opts.WorkDir
				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
			}
			return nil
		},
	}

	command.AddCommand(
		upCommand(&opts, backend),
		downCommand(&opts, backend),
		startCommand(&opts, backend),
		restartCommand(&opts, backend),
		stopCommand(&opts, backend),
		psCommand(&opts, backend),
		listCommand(backend),
		logsCommand(&opts, backend),
		convertCommand(&opts, backend),
		killCommand(&opts, backend),
		runCommand(&opts, dockerCli, backend),
		removeCommand(&opts, backend),
		execCommand(&opts, dockerCli, backend),
		pauseCommand(&opts, backend),
		unpauseCommand(&opts, backend),
		topCommand(&opts, backend),
		eventsCommand(&opts, backend),
		portCommand(&opts, backend),
		imagesCommand(&opts, backend),
		versionCommand(),
		buildCommand(&opts, backend),
		pushCommand(&opts, backend),
		pullCommand(&opts, backend),
		createCommand(&opts, backend),
		copyCommand(&opts, backend),
	)
	command.Flags().SetInterspersed(false)
	opts.addProjectFlags(command.Flags())
	command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
	command.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
	command.Flags().MarkHidden("version") //nolint:errcheck
	command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
	command.Flags().MarkHidden("no-ansi") //nolint:errcheck
	command.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
	command.Flags().MarkHidden("verbose") //nolint:errcheck
	return command
}
<commit_msg>Don't use ansi even when deprecated option is requested<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 compose

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	dockercli "github.com/docker/cli/cli"
	"github.com/docker/cli/cli-plugins/manager"
	"github.com/docker/cli/cli/command"
	"github.com/morikuni/aec"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/docker/compose/v2/pkg/api"
	"github.com/docker/compose/v2/pkg/compose"
	"github.com/docker/compose/v2/pkg/progress"
	"github.com/docker/compose/v2/pkg/utils"
)

// Command defines a compose CLI command as a func with args
type Command func(context.Context, []string) error

// CobraCommand defines a cobra command function
type CobraCommand func(context.Context, *cobra.Command, []string) error

// AdaptCmd adapt a CobraCommand func to cobra library
func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
	return func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		contextString := fmt.Sprintf("%s", ctx)
		if !strings.HasSuffix(contextString, ".WithCancel") { // need to handle cancel
			cancellableCtx, cancel := context.WithCancel(cmd.Context())
			ctx = cancellableCtx
			s := make(chan os.Signal, 1)
			signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
			go func() {
				<-s
				cancel()
			}()
		}
		err := fn(ctx, cmd, args)
		var composeErr compose.Error
		if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
			err = dockercli.StatusError{
				StatusCode: 130,
				Status:     compose.CanceledStatus,
			}
		}
		if errors.As(err, &composeErr) {
			err = dockercli.StatusError{
				StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
				Status:     err.Error(),
			}
		}
		return err
	}
}

// Adapt a Command func to cobra library
func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
	return AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
		return fn(ctx, args)
	})
}

type projectOptions struct {
	ProjectName   string
	Profiles      []string
	ConfigPaths   []string
	WorkDir       string
	ProjectDir    string
	EnvFile       string
	Compatibility bool
}

// ProjectFunc does stuff within a types.Project
type ProjectFunc func(ctx context.Context, project *types.Project) error

// ProjectServicesFunc does stuff within a types.Project and a selection of services
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error

// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
	return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
		return fn(ctx, project)
	})
}

// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
func (o *projectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
	return Adapt(func(ctx context.Context, args []string) error {
		project, err := o.toProject(args, cli.WithResolvedPaths(true))
		if err != nil {
			return err
		}

		return fn(ctx, project, args)
	})
}

func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
	f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
	f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
	f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
	f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.")
	f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
	f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
	f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
	_ = f.MarkHidden("workdir")
}

func (o *projectOptions) toProjectName() (string, error) {
	if o.ProjectName != "" {
		return o.ProjectName, nil
	}

	envProjectName := os.Getenv("COMPOSE_PROJECT_NAME")
	if envProjectName != "" {
		return envProjectName, nil
	}

	project, err := o.toProject(nil)
	if err != nil {
		return "", err
	}
	return project.Name, nil
}

func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
	options, err := o.toProjectOptions(po...)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	project, err := cli.ProjectFromOptions(options)
	if err != nil {
		return nil, compose.WrapComposeError(err)
	}

	if o.Compatibility || utils.StringToBool(project.Environment["COMPOSE_COMPATIBILITY"]) {
		compose.Separator = "_"
	}

	ef := o.EnvFile
	if ef != "" && !filepath.IsAbs(ef) {
		ef, err = filepath.Abs(ef)
		if err != nil {
			return nil, err
		}
	}
	for i, s := range project.Services {
		s.CustomLabels = map[string]string{
			api.ProjectLabel:     project.Name,
			api.ServiceLabel:     s.Name,
			api.VersionLabel:     api.ComposeVersion,
			api.WorkingDirLabel:  project.WorkingDir,
			api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","),
			api.OneoffLabel:      "False", // default, will be overridden by `run` command
		}
		if ef != "" {
			s.CustomLabels[api.EnvironmentFileLabel] = ef
		}
		project.Services[i] = s
	}

	if len(services) > 0 {
		s, err := project.GetServices(services...)
		if err != nil {
			return nil, err
		}
		o.Profiles = append(o.Profiles, s.GetProfiles()...)
	}

	if profiles, ok := options.Environment["COMPOSE_PROFILES"]; ok {
		o.Profiles = append(o.Profiles, strings.Split(profiles, ",")...)
	}

	project.ApplyProfiles(o.Profiles)

	project.WithoutUnnecessaryResources()

	err = project.ForServices(services)
	return project, err
}

func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
	return cli.NewProjectOptions(o.ConfigPaths,
		append(po,
			cli.WithWorkingDirectory(o.ProjectDir),
			cli.WithEnvFile(o.EnvFile),
			cli.WithDotEnv,
			cli.WithOsEnv,
			cli.WithConfigFileEnv,
			cli.WithDefaultConfigPath,
			cli.WithName(o.ProjectName))...)
}

// PluginName is the name of the plugin
const PluginName = "compose"

// RunningAsStandalone detects when running as a standalone program
func RunningAsStandalone() bool {
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
}

// RootCommand returns the compose command with its child commands
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
	opts := projectOptions{}
	var (
		ansi    string
		noAnsi  bool
		verbose bool
		version bool
	)
	command := &cobra.Command{
		Short:            "Docker Compose",
		Use:              PluginName,
		TraverseChildren: true,
		// By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) !
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) == 0 {
				return cmd.Help()
			}
			if version {
				return versionCommand().Execute()
			}
			_ = cmd.Help()
			return dockercli.StatusError{
				StatusCode: compose.CommandSyntaxFailure.ExitCode,
				Status:     fmt.Sprintf("unknown docker command: %q", "compose "+args[0]),
			}
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			parent := cmd.Root()
			if parent != nil {
				parentPrerun := parent.PersistentPreRunE
				if parentPrerun != nil {
					err := parentPrerun(cmd, args)
					if err != nil {
						return err
					}
				}
			}
			if noAnsi {
				if ansi != "auto" {
					return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
				}
				ansi = "never"
				fmt.Fprint(os.Stderr, "option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n")
			}
			if verbose {
				logrus.SetLevel(logrus.TraceLevel)
			}
			formatter.SetANSIMode(ansi)
			switch ansi {
			case "never":
				progress.Mode = progress.ModePlain
			case "tty":
				progress.Mode = progress.ModeTTY
			}
			if opts.WorkDir != "" {
				if opts.ProjectDir != "" {
					return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
				}
				opts.ProjectDir = opts.WorkDir
				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
			}
			return nil
		},
	}

	command.AddCommand(
		upCommand(&opts, backend),
		downCommand(&opts, backend),
		startCommand(&opts, backend),
		restartCommand(&opts, backend),
		stopCommand(&opts, backend),
		psCommand(&opts, backend),
		listCommand(backend),
		logsCommand(&opts, backend),
		convertCommand(&opts, backend),
		killCommand(&opts, backend),
		runCommand(&opts, dockerCli, backend),
		removeCommand(&opts, backend),
		execCommand(&opts, dockerCli, backend),
		pauseCommand(&opts, backend),
		unpauseCommand(&opts, backend),
		topCommand(&opts, backend),
		eventsCommand(&opts, backend),
		portCommand(&opts, backend),
		imagesCommand(&opts, backend),
		versionCommand(),
		buildCommand(&opts, backend),
		pushCommand(&opts, backend),
		pullCommand(&opts, backend),
		createCommand(&opts, backend),
		copyCommand(&opts, backend),
	)
	command.Flags().SetInterspersed(false)
	opts.addProjectFlags(command.Flags())
	command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
	command.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
	command.Flags().MarkHidden("version") //nolint:errcheck
	command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
	command.Flags().MarkHidden("no-ansi") //nolint:errcheck
	command.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
	command.Flags().MarkHidden("verbose") //nolint:errcheck
	return command
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"

	cliconfig "github.com/docker/docker/cli/config"
	"github.com/docker/docker/daemon/config"
	"github.com/docker/docker/opts"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/spf13/pflag"
)

const (
	// DefaultCaFile is the default filename for the CA pem file
	DefaultCaFile = "ca.pem"
	// DefaultKeyFile is the default filename for the key pem file
	DefaultKeyFile = "key.pem"
	// DefaultCertFile is the default filename for the cert pem file
	DefaultCertFile = "cert.pem"
	// FlagTLSVerify is the flag name for the TLS verification option
	FlagTLSVerify = "tlsverify"
	// FlagTLS is the flag name for the TLS option
	FlagTLS = "tls"
	// DefaultTLSValue is the default value used for setting the tls option for tcp connections
	DefaultTLSValue = false
)

var (
	dockerCertPath  = os.Getenv("DOCKER_CERT_PATH")
	dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
)

type daemonOptions struct {
	configFile   string
	daemonConfig *config.Config
	flags        *pflag.FlagSet
	Debug        bool
	Hosts        []string
	LogLevel     string
	TLS          bool
	TLSVerify    bool
	TLSOptions   *tlsconfig.Options
	Validate     bool
}

// newDaemonOptions returns a new daemonFlags
func newDaemonOptions(config *config.Config) *daemonOptions {
	return &daemonOptions{
		daemonConfig: config,
	}
}

// InstallFlags adds flags for the common options on the FlagSet
func (o *daemonOptions) InstallFlags(flags *pflag.FlagSet) {
	if dockerCertPath == "" {
		// cliconfig.Dir returns $DOCKER_CONFIG or ~/.docker.
		// cliconfig.Dir does not look up $XDG_CONFIG_HOME
		dockerCertPath = cliconfig.Dir()
	}

	flags.BoolVarP(&o.Debug, "debug", "D", false, "Enable debug mode")
	flags.BoolVar(&o.Validate, "validate", false, "Validate configuration file and exit")
	flags.StringVarP(&o.LogLevel, "log-level", "l", "info", `Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")`)
	flags.BoolVar(&o.TLS, FlagTLS, DefaultTLSValue, "Use TLS; implied by --tlsverify")
	flags.BoolVar(&o.TLSVerify, FlagTLSVerify, dockerTLSVerify || DefaultTLSValue, "Use TLS and verify the remote")

	// TODO use flag flags.String("identity"}, "i", "", "Path to libtrust key file")

	o.TLSOptions = &tlsconfig.Options{
		CAFile:   filepath.Join(dockerCertPath, DefaultCaFile),
		CertFile: filepath.Join(dockerCertPath, DefaultCertFile),
		KeyFile:  filepath.Join(dockerCertPath, DefaultKeyFile),
	}
	tlsOptions := o.TLSOptions
	flags.Var(opts.NewQuotedString(&tlsOptions.CAFile), "tlscacert", "Trust certs signed only by this CA")
	flags.Var(opts.NewQuotedString(&tlsOptions.CertFile), "tlscert", "Path to TLS certificate file")
	flags.Var(opts.NewQuotedString(&tlsOptions.KeyFile), "tlskey", "Path to TLS key file")

	hostOpt := opts.NewNamedListOptsRef("hosts", &o.Hosts, opts.ValidateHost)
	flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
}

// SetDefaultOptions sets default values for options after flag parsing is
// complete
func (o *daemonOptions) SetDefaultOptions(flags *pflag.FlagSet) {
	// Regardless of whether the user sets it to true or false, if they
	// specify --tlsverify at all then we need to turn on TLS
	// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
	// to check that here as well
	if flags.Changed(FlagTLSVerify) || o.TLSVerify {
		o.TLS = true
	}

	if o.TLS && !flags.Changed(FlagTLSVerify) {
		// Enable tls verification unless explicitly disabled
		o.TLSVerify = true
	}

	if !o.TLS {
		o.TLSOptions = nil
	} else {
		tlsOptions := o.TLSOptions
		tlsOptions.InsecureSkipVerify = !o.TLSVerify

		// Reset CertFile and KeyFile to empty string if the user did not specify
		// the respective flags and the respective default files were not found.
		if !flags.Changed("tlscert") {
			if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
				tlsOptions.CertFile = ""
			}
		}
		if !flags.Changed("tlskey") {
			if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
				tlsOptions.KeyFile = ""
			}
		}
	}
}
<commit_msg>Make validate flag description more generic<commit_after>package main

import (
	"os"
	"path/filepath"

	cliconfig "github.com/docker/docker/cli/config"
	"github.com/docker/docker/daemon/config"
	"github.com/docker/docker/opts"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/spf13/pflag"
)

const (
	// DefaultCaFile is the default filename for the CA pem file
	DefaultCaFile = "ca.pem"
	// DefaultKeyFile is the default filename for the key pem file
	DefaultKeyFile = "key.pem"
	// DefaultCertFile is the default filename for the cert pem file
	DefaultCertFile = "cert.pem"
	// FlagTLSVerify is the flag name for the TLS verification option
	FlagTLSVerify = "tlsverify"
	// FlagTLS is the flag name for the TLS option
	FlagTLS = "tls"
	// DefaultTLSValue is the default value used for setting the tls option for tcp connections
	DefaultTLSValue = false
)

var (
	dockerCertPath  = os.Getenv("DOCKER_CERT_PATH")
	dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
)

type daemonOptions struct {
	configFile   string
	daemonConfig *config.Config
	flags        *pflag.FlagSet
	Debug        bool
	Hosts        []string
	LogLevel     string
	TLS          bool
	TLSVerify    bool
	TLSOptions   *tlsconfig.Options
	Validate     bool
}

// newDaemonOptions returns a new daemonFlags
func newDaemonOptions(config *config.Config) *daemonOptions {
	return &daemonOptions{
		daemonConfig: config,
	}
}

// InstallFlags adds flags for the common options on the FlagSet
func (o *daemonOptions) InstallFlags(flags *pflag.FlagSet) {
	if dockerCertPath == "" {
		// cliconfig.Dir returns $DOCKER_CONFIG or ~/.docker.
		// cliconfig.Dir does not look up $XDG_CONFIG_HOME
		dockerCertPath = cliconfig.Dir()
	}

	flags.BoolVarP(&o.Debug, "debug", "D", false, "Enable debug mode")
	flags.BoolVar(&o.Validate, "validate", false, "Validate daemon configuration and exit")
	flags.StringVarP(&o.LogLevel, "log-level", "l", "info", `Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")`)
	flags.BoolVar(&o.TLS, FlagTLS, DefaultTLSValue, "Use TLS; implied by --tlsverify")
	flags.BoolVar(&o.TLSVerify, FlagTLSVerify, dockerTLSVerify || DefaultTLSValue, "Use TLS and verify the remote")

	// TODO use flag flags.String("identity"}, "i", "", "Path to libtrust key file")

	o.TLSOptions = &tlsconfig.Options{
		CAFile:   filepath.Join(dockerCertPath, DefaultCaFile),
		CertFile: filepath.Join(dockerCertPath, DefaultCertFile),
		KeyFile:  filepath.Join(dockerCertPath, DefaultKeyFile),
	}
	tlsOptions := o.TLSOptions
	flags.Var(opts.NewQuotedString(&tlsOptions.CAFile), "tlscacert", "Trust certs signed only by this CA")
	flags.Var(opts.NewQuotedString(&tlsOptions.CertFile), "tlscert", "Path to TLS certificate file")
	flags.Var(opts.NewQuotedString(&tlsOptions.KeyFile), "tlskey", "Path to TLS key file")

	hostOpt := opts.NewNamedListOptsRef("hosts", &o.Hosts, opts.ValidateHost)
	flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
}

// SetDefaultOptions sets default values for options after flag parsing is
// complete
func (o *daemonOptions) SetDefaultOptions(flags *pflag.FlagSet) {
	// Regardless of whether the user sets it to true or false, if they
	// specify --tlsverify at all then we need to turn on TLS
	// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
	// to check that here as well
	if flags.Changed(FlagTLSVerify) || o.TLSVerify {
		o.TLS = true
	}

	if o.TLS && !flags.Changed(FlagTLSVerify) {
		// Enable tls verification unless explicitly disabled
		o.TLSVerify = true
	}

	if !o.TLS {
		o.TLSOptions = nil
	} else {
		tlsOptions := o.TLSOptions
		tlsOptions.InsecureSkipVerify = !o.TLSVerify

		// Reset CertFile and KeyFile to empty string if the user did not specify
		// the respective flags and the respective default files were not found.
		if !flags.Changed("tlscert") {
			if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
				tlsOptions.CertFile = ""
			}
		}
		if !flags.Changed("tlskey") {
			if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
				tlsOptions.KeyFile = ""
			}
		}
	}
}
<|endoftext|>