<commit_before>package myirmaserver

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/go-errors/errors"
	_ "github.com/jackc/pgx/stdlib"
	"github.com/privacybydesign/irmago/server"
)

type myirmaPostgresDB struct {
	db          *sql.DB
	deleteDelay int
}

const EMAIL_TOKEN_VALIDITY = 60 // Ammount of time an email login token is valid (in minutes)

func NewPostgresDatabase(connstring string, deleteDelay int) (MyirmaDB, error) {
	db, err := sql.Open("pgx", connstring)
	if err != nil {
		return nil, err
	}
	return &myirmaPostgresDB{
		db:          db,
		deleteDelay: deleteDelay,
	}, nil
}

func (db *myirmaPostgresDB) GetUserID(username string) (int64, error) {
	res, err := db.db.Query("SELECT id FROM irma.users WHERE username = $1", username)
	if err != nil {
		return 0, err
	}
	defer res.Close()
	if !res.Next() {
		return 0, ErrUserNotFound
	}
	var id int64
	err = res.Scan(&id)
	return id, err
}

func (db *myirmaPostgresDB) VerifyEmailToken(token string) (int64, error) {
	res, err := db.db.Query("SELECT user_id, email FROM irma.email_verification_tokens WHERE token = $1 AND expiry >= $2", token, time.Now().Unix())
	if err != nil {
		return 0, err
	}
	defer res.Close()
	if !res.Next() {
		return 0, ErrUserNotFound
	}
	var email string
	var id int64
	err = res.Scan(&id, &email)
	if err != nil {
		return 0, err
	}

	err = db.AddEmail(id, email)
	if err != nil {
		return 0, err
	}

	// Beyond this point, errors are no longer relevant for frontend, so only log
	delres, err := db.db.Exec("DELETE FROM irma.email_verification_tokens WHERE token = $1", token)
	if err != nil {
		server.LogError(err)
		return id, nil
	}
	aff, err := delres.RowsAffected()
	if err != nil {
		server.LogError(err)
		return id, nil
	}
	if aff != 1 {
		server.LogError(errors.Errorf("Unexpected number of deleted records %d for token", aff))
		return id, nil
	}
	return id, nil
}

func (db *myirmaPostgresDB) RemoveUser(id int64) error {
	res, err := db.db.Exec("UPDATE irma.users SET coredata = NULL, delete_on = $2 WHERE id = $1 AND coredata IS NOT NULL",
		id,
		time.Now().Add(time.Duration(24*db.deleteDelay)*time.Hour).Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff == 0 {
		return ErrUserNotFound
	}
	return nil
}

func (db *myirmaPostgresDB) AddEmailLoginToken(email, token string) error {
	// Check if email address exists in database
	eres, err := db.db.Query("SELECT 1 FROM irma.emails WHERE email = $1 AND (delete_on >= $2 OR delete_on IS NULL) LIMIT 1",
		email, time.Now().Unix())
	if err != nil {
		return err
	}
	defer eres.Close()
	if !eres.Next() {
		return ErrUserNotFound
	}

	// insert and verify
	res, err := db.db.Exec("INSERT INTO irma.email_login_tokens (token, email, expiry) VALUES ($1, $2, $3)",
		token,
		email,
		time.Now().Add(EMAIL_TOKEN_VALIDITY*time.Minute).Unix())
	fmt.Println(time.Now().Add(EMAIL_TOKEN_VALIDITY*time.Minute).Unix(), " ", time.Now().Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return errors.Errorf("Unexpected number of affected rows %d on token insert", aff)
	}

	return nil
}

func (db *myirmaPostgresDB) LoginTokenGetCandidates(token string) ([]LoginCandidate, error) {
	res, err := db.db.Query(`SELECT username, last_seen FROM irma.users WHERE id IN
							     (SELECT user_id FROM irma.emails WHERE (delete_on >= $2 OR delete_on is NULL) AND
									 emails.email = (SELECT email FROM irma.email_login_tokens WHERE token = $1 AND expiry >= $2))`,
		token, time.Now().Unix())
	if err != nil {
		return nil, err
	}
	defer res.Close()
	candidates := []LoginCandidate{}
	for res.Next() {
		candidate := LoginCandidate{}
		err = res.Scan(&candidate.Username, &candidate.LastActive)
		if err != nil {
			return nil, err
		}
		candidates = append(candidates, candidate)
	}
	if len(candidates) == 0 {
		return nil, ErrUserNotFound
	}
	return candidates, nil
}

func (db *myirmaPostgresDB) LoginTokenGetEmail(token string) (string, error) {
	res, err := db.db.Query("SELECT email FROM irma.email_login_tokens WHERE token = $1 AND expiry >= $2", token, time.Now().Unix())
	if err != nil {
		return "", err
	}
	defer res.Close()
	if !res.Next() {
		return "", ErrUserNotFound
	}
	var email string
	err = res.Scan(&email)
	return email, err
}

func (db *myirmaPostgresDB) TryUserLoginToken(token, username string) (bool, error) {
	res, err := db.db.Query(`SELECT 1 FROM irma.users INNER JOIN irma.emails ON users.id = emails.user_id WHERE
								 username = $1 AND (emails.delete_on >= $3 OR emails.delete_on IS NULL) AND
								 email = (SELECT email FROM irma.email_login_tokens WHERE token = $2 AND expiry >= $3)`,
		username, token, time.Now().Unix())
	if err != nil {
		return false, err
	}
	defer res.Close()
	if !res.Next() {
		return false, ErrUserNotFound
	}

	// Successfull deletion of the token can only occur once, so we use that to signal ok to login
	delres, err := db.db.Exec("DELETE FROM irma.email_login_tokens WHERE token = $1", token)
	if err != nil {
		return false, err
	}
	aff, err := delres.RowsAffected()
	if err != nil {
		return false, err
	}
	if aff != 1 {
		return false, nil
	}
	return true, nil
}

func (db *myirmaPostgresDB) GetUserInformation(id int64) (UserInformation, error) {
	var result UserInformation

	// fetch username
	res, err := db.db.Query("SELECT username, language, (delete_on IS NOT NULL) AS delete_in_progress FROM irma.users WHERE id = $1", id)
	if err != nil {
		return UserInformation{}, err
	}
	defer res.Close()
	if !res.Next() {
		return UserInformation{}, ErrUserNotFound
	}
	err = res.Scan(&result.Username, &result.language, &result.DeleteInProgress)
	if err != nil {
		return UserInformation{}, err
	}

	// fetch email addresses
	rese, err := db.db.Query("SELECT email, (delete_on IS NOT NULL) AS delete_in_progress FROM irma.emails WHERE user_id = $1 AND (delete_on >= $2 OR delete_on IS NULL)",
		id, time.Now().Unix())
	if err != nil {
		return UserInformation{}, err
	}
	defer res.Close()
	for rese.Next() {
		var email UserEmail
		err = rese.Scan(&email.Email, &email.DeleteInProgress)
		if err != nil {
			return UserInformation{}, err
		}
		result.Emails = append(result.Emails, email)
	}

	return result, nil
}

func (db *myirmaPostgresDB) GetLogs(id int64, offset, ammount int) ([]LogEntry, error) {
	res, err := db.db.Query("SELECT time, event, param FROM irma.log_entry_records WHERE user_id = $1 ORDER BY time DESC OFFSET $2 LIMIT $3",
		id, offset, ammount)
	if err != nil {
		return nil, err
	}
	defer res.Close()
	var result []LogEntry
	for res.Next() {
		var curEntry LogEntry
		var param *string
		err = res.Scan(&curEntry.Timestamp, &curEntry.Event, &param)
		if err != nil {
			return nil, err
		}
		if param == nil {
			curEntry.Param = ""
		} else {
			curEntry.Param = *param
		}
		result = append(result, curEntry)
	}
	return result, nil
}

func (db *myirmaPostgresDB) AddEmail(id int64, email string) error {
	// Try to restore email in process of deletion
	res, err := db.db.Exec("UPDATE irma.emails SET delete_on = NULL WHERE user_id = $1 AND email = $2", id, email)
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff == 1 {
		return nil
	}

	// Fall back to adding new one
	res, err = db.db.Exec("INSERT INTO irma.emails (user_id, email) VALUES ($1, $2)", id, email)
	if err != nil {
		return err
	}
	aff, err = res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return errors.Errorf("Unexpected number of affected rows %d for email addition", aff)
	}
	return nil
}

func (db *myirmaPostgresDB) RemoveEmail(id int64, email string) error {
	res, err := db.db.Exec("UPDATE irma.emails SET delete_on = $3 WHERE user_id = $1 AND email = $2 AND delete_on IS NULL",
		id,
		email,
		time.Now().Add(time.Duration(24*db.deleteDelay)*time.Hour).Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return ErrUserNotFound
	}
	return nil
}

func (db *myirmaPostgresDB) SetSeen(id int64) error {
	res, err := db.db.Exec("UPDATE irma.users SET last_seen = $1 WHERE id = $2", time.Now().Unix(), id)
	if err != nil {
		return err
	}
	c, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if c != 1 {
		return ErrUserNotFound
	}
	return nil
}
<commit_msg>Fixed small bug in how myirmaserver determined deletion tatus of account.<commit_after>package myirmaserver

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/go-errors/errors"
	_ "github.com/jackc/pgx/stdlib"
	"github.com/privacybydesign/irmago/server"
)

type myirmaPostgresDB struct {
	db          *sql.DB
	deleteDelay int
}

const EMAIL_TOKEN_VALIDITY = 60 // Ammount of time an email login token is valid (in minutes)

func NewPostgresDatabase(connstring string, deleteDelay int) (MyirmaDB, error) {
	db, err := sql.Open("pgx", connstring)
	if err != nil {
		return nil, err
	}
	return &myirmaPostgresDB{
		db:          db,
		deleteDelay: deleteDelay,
	}, nil
}

func (db *myirmaPostgresDB) GetUserID(username string) (int64, error) {
	res, err := db.db.Query("SELECT id FROM irma.users WHERE username = $1", username)
	if err != nil {
		return 0, err
	}
	defer res.Close()
	if !res.Next() {
		return 0, ErrUserNotFound
	}
	var id int64
	err = res.Scan(&id)
	return id, err
}

func (db *myirmaPostgresDB) VerifyEmailToken(token string) (int64, error) {
	res, err := db.db.Query("SELECT user_id, email FROM irma.email_verification_tokens WHERE token = $1 AND expiry >= $2", token, time.Now().Unix())
	if err != nil {
		return 0, err
	}
	defer res.Close()
	if !res.Next() {
		return 0, ErrUserNotFound
	}
	var email string
	var id int64
	err = res.Scan(&id, &email)
	if err != nil {
		return 0, err
	}

	err = db.AddEmail(id, email)
	if err != nil {
		return 0, err
	}

	// Beyond this point, errors are no longer relevant for frontend, so only log
	delres, err := db.db.Exec("DELETE FROM irma.email_verification_tokens WHERE token = $1", token)
	if err != nil {
		server.LogError(err)
		return id, nil
	}
	aff, err := delres.RowsAffected()
	if err != nil {
		server.LogError(err)
		return id, nil
	}
	if aff != 1 {
		server.LogError(errors.Errorf("Unexpected number of deleted records %d for token", aff))
		return id, nil
	}
	return id, nil
}

func (db *myirmaPostgresDB) RemoveUser(id int64) error {
	res, err := db.db.Exec("UPDATE irma.users SET coredata = NULL, delete_on = $2 WHERE id = $1 AND coredata IS NOT NULL",
		id,
		time.Now().Add(time.Duration(24*db.deleteDelay)*time.Hour).Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff == 0 {
		return ErrUserNotFound
	}
	return nil
}

func (db *myirmaPostgresDB) AddEmailLoginToken(email, token string) error {
	// Check if email address exists in database
	eres, err := db.db.Query("SELECT 1 FROM irma.emails WHERE email = $1 AND (delete_on >= $2 OR delete_on IS NULL) LIMIT 1",
		email, time.Now().Unix())
	if err != nil {
		return err
	}
	defer eres.Close()
	if !eres.Next() {
		return ErrUserNotFound
	}

	// insert and verify
	res, err := db.db.Exec("INSERT INTO irma.email_login_tokens (token, email, expiry) VALUES ($1, $2, $3)",
		token,
		email,
		time.Now().Add(EMAIL_TOKEN_VALIDITY*time.Minute).Unix())
	fmt.Println(time.Now().Add(EMAIL_TOKEN_VALIDITY*time.Minute).Unix(), " ", time.Now().Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return errors.Errorf("Unexpected number of affected rows %d on token insert", aff)
	}

	return nil
}

func (db *myirmaPostgresDB) LoginTokenGetCandidates(token string) ([]LoginCandidate, error) {
	res, err := db.db.Query(`SELECT username, last_seen FROM irma.users WHERE id IN
							     (SELECT user_id FROM irma.emails WHERE (delete_on >= $2 OR delete_on is NULL) AND
									 emails.email = (SELECT email FROM irma.email_login_tokens WHERE token = $1 AND expiry >= $2))`,
		token, time.Now().Unix())
	if err != nil {
		return nil, err
	}
	defer res.Close()
	candidates := []LoginCandidate{}
	for res.Next() {
		candidate := LoginCandidate{}
		err = res.Scan(&candidate.Username, &candidate.LastActive)
		if err != nil {
			return nil, err
		}
		candidates = append(candidates, candidate)
	}
	if len(candidates) == 0 {
		return nil, ErrUserNotFound
	}
	return candidates, nil
}

func (db *myirmaPostgresDB) LoginTokenGetEmail(token string) (string, error) {
	res, err := db.db.Query("SELECT email FROM irma.email_login_tokens WHERE token = $1 AND expiry >= $2", token, time.Now().Unix())
	if err != nil {
		return "", err
	}
	defer res.Close()
	if !res.Next() {
		return "", ErrUserNotFound
	}
	var email string
	err = res.Scan(&email)
	return email, err
}

func (db *myirmaPostgresDB) TryUserLoginToken(token, username string) (bool, error) {
	res, err := db.db.Query(`SELECT 1 FROM irma.users INNER JOIN irma.emails ON users.id = emails.user_id WHERE
								 username = $1 AND (emails.delete_on >= $3 OR emails.delete_on IS NULL) AND
								 email = (SELECT email FROM irma.email_login_tokens WHERE token = $2 AND expiry >= $3)`,
		username, token, time.Now().Unix())
	if err != nil {
		return false, err
	}
	defer res.Close()
	if !res.Next() {
		return false, ErrUserNotFound
	}

	// Successfull deletion of the token can only occur once, so we use that to signal ok to login
	delres, err := db.db.Exec("DELETE FROM irma.email_login_tokens WHERE token = $1", token)
	if err != nil {
		return false, err
	}
	aff, err := delres.RowsAffected()
	if err != nil {
		return false, err
	}
	if aff != 1 {
		return false, nil
	}
	return true, nil
}

func (db *myirmaPostgresDB) GetUserInformation(id int64) (UserInformation, error) {
	var result UserInformation

	// fetch username
	res, err := db.db.Query("SELECT username, language, (coredata IS NULL) AS delete_in_progress FROM irma.users WHERE id = $1", id)
	if err != nil {
		return UserInformation{}, err
	}
	defer res.Close()
	if !res.Next() {
		return UserInformation{}, ErrUserNotFound
	}
	err = res.Scan(&result.Username, &result.language, &result.DeleteInProgress)
	if err != nil {
		return UserInformation{}, err
	}

	// fetch email addresses
	rese, err := db.db.Query("SELECT email, (delete_on IS NOT NULL) AS delete_in_progress FROM irma.emails WHERE user_id = $1 AND (delete_on >= $2 OR delete_on IS NULL)",
		id, time.Now().Unix())
	if err != nil {
		return UserInformation{}, err
	}
	defer res.Close()
	for rese.Next() {
		var email UserEmail
		err = rese.Scan(&email.Email, &email.DeleteInProgress)
		if err != nil {
			return UserInformation{}, err
		}
		result.Emails = append(result.Emails, email)
	}

	return result, nil
}

func (db *myirmaPostgresDB) GetLogs(id int64, offset, ammount int) ([]LogEntry, error) {
	res, err := db.db.Query("SELECT time, event, param FROM irma.log_entry_records WHERE user_id = $1 ORDER BY time DESC OFFSET $2 LIMIT $3",
		id, offset, ammount)
	if err != nil {
		return nil, err
	}
	defer res.Close()
	var result []LogEntry
	for res.Next() {
		var curEntry LogEntry
		var param *string
		err = res.Scan(&curEntry.Timestamp, &curEntry.Event, &param)
		if err != nil {
			return nil, err
		}
		if param == nil {
			curEntry.Param = ""
		} else {
			curEntry.Param = *param
		}
		result = append(result, curEntry)
	}
	return result, nil
}

func (db *myirmaPostgresDB) AddEmail(id int64, email string) error {
	// Try to restore email in process of deletion
	res, err := db.db.Exec("UPDATE irma.emails SET delete_on = NULL WHERE user_id = $1 AND email = $2", id, email)
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff == 1 {
		return nil
	}

	// Fall back to adding new one
	res, err = db.db.Exec("INSERT INTO irma.emails (user_id, email) VALUES ($1, $2)", id, email)
	if err != nil {
		return err
	}
	aff, err = res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return errors.Errorf("Unexpected number of affected rows %d for email addition", aff)
	}
	return nil
}

func (db *myirmaPostgresDB) RemoveEmail(id int64, email string) error {
	res, err := db.db.Exec("UPDATE irma.emails SET delete_on = $3 WHERE user_id = $1 AND email = $2 AND delete_on IS NULL",
		id,
		email,
		time.Now().Add(time.Duration(24*db.deleteDelay)*time.Hour).Unix())
	if err != nil {
		return err
	}
	aff, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if aff != 1 {
		return ErrUserNotFound
	}
	return nil
}

func (db *myirmaPostgresDB) SetSeen(id int64) error {
	res, err := db.db.Exec("UPDATE irma.users SET last_seen = $1 WHERE id = $2", time.Now().Unix(), id)
	if err != nil {
		return err
	}
	c, err := res.RowsAffected()
	if err != nil {
		return err
	}
	if c != 1 {
		return ErrUserNotFound
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	apiURL = "https://domai.nr/api/json/search?client_id=domainr_command_line_app&q="
)

type Result struct {
	Domain       string
	Availability string
}

type SearchResults struct {
	Query   string
	Results []Result
}

func main() {

	if len(os.Args) < 2 {
		fmt.Println("Missing search query. Specify a string to search domainr for.")
		os.Exit(1)
	}

	var query string = os.Args[1]

	httpResponse, err := http.Get(apiURL + query)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	defer httpResponse.Body.Close()
	body, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var sr SearchResults

	// Decode json string into custom structs.
	json.Unmarshal(body, &sr)

	// Print results to stdout
	fmt.Printf("\n Results for \"%s\"\n\n", sr.Query)
	for _, result := range sr.Results {
		var available string
		switch result.Availability {
		case "available":
			available = "✔"
		default:
			available = "✘"
		}
		fmt.Printf("     %s %s\n", available, result.Domain)
	}
	fmt.Printf("\n")
}
<commit_msg>Print to buffer before printing to stdout.<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	apiURL = "https://domai.nr/api/json/search?client_id=domainr_command_line_app&q="
)

type Result struct {
	Domain       string
	Availability string
}

type SearchResults struct {
	Query   string
	Results []Result
}

func main() {

	if len(os.Args) < 2 {
		fmt.Println("Missing search query. Specify a string to search domainr for.")
		os.Exit(1)
	}

	var query string = os.Args[1]

	httpResponse, err := http.Get(apiURL + query)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	defer httpResponse.Body.Close()
	body, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var sr SearchResults

	// Decode json string into custom structs.
	json.Unmarshal(body, &sr)

	buf := bufio.NewWriter(os.Stdout)

	// Print results to stdout
	fmt.Fprintf(buf, "\n Results for \"%s\"\n\n", sr.Query)
	for _, result := range sr.Results {
		var available string
		switch result.Availability {
		case "available":
			available = "✔"
		default:
			available = "✘"
		}
		fmt.Fprintf(buf, "     %s %s\n", available, result.Domain)
	}
	fmt.Fprintf(buf, "\n")
	buf.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/aymerick/douceur/inliner"
	"github.com/aymerick/douceur/parser"
)

const (
	VERSION = "0.0.1"
)

var (
	flagVersion bool
)

func init() {
	flag.BoolVar(&flagVersion, "version", false, "Display version")
}

func main() {
	flag.Parse()

	if flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	args := flag.Args()

	if len(args) == 0 {
		fmt.Println("No command supplied")
		os.Exit(1)
	}

	switch args[0] {
	case "parse":
		if len(args) < 2 {
			fmt.Println("Missing file path")
			os.Exit(1)
		}

		parseCSS(args[1])
	case "inline":
		if len(args) < 2 {
			fmt.Println("Missing file path")
			os.Exit(1)
		}

		inlineCSS(args[1])
	default:
		fmt.Println("Unexpected command: ", args[0])
		os.Exit(1)
	}
}

// parse and display CSS file
func parseCSS(filePath string) {
	input := readFile(filePath)

	stylesheet, err := parser.Parse(string(input))
	if err != nil {
		fmt.Println("Parsing error: ", err)
		os.Exit(1)
	}

	fmt.Println(stylesheet.String())
}

// inlines CSS into HTML and display result
func inlineCSS(filePath string) {
	input := readFile(filePath)

	output, err := inliner.Inline(string(input))
	if err != nil {
		fmt.Println("Inlining error: ", err)
		os.Exit(1)
	}

	fmt.Println(output)
}

func readFile(filePath string) []byte {
	file, err := ioutil.ReadFile(filePath)
	if err != nil {
		fmt.Println("Failed to open file: ", filePath, err)
		os.Exit(1)
	}

	return file
}
<commit_msg>Bump version: 0.1.0<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/aymerick/douceur/inliner"
	"github.com/aymerick/douceur/parser"
)

const (
	VERSION = "0.1.0"
)

var (
	flagVersion bool
)

func init() {
	flag.BoolVar(&flagVersion, "version", false, "Display version")
}

func main() {
	flag.Parse()

	if flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	args := flag.Args()

	if len(args) == 0 {
		fmt.Println("No command supplied")
		os.Exit(1)
	}

	switch args[0] {
	case "parse":
		if len(args) < 2 {
			fmt.Println("Missing file path")
			os.Exit(1)
		}

		parseCSS(args[1])
	case "inline":
		if len(args) < 2 {
			fmt.Println("Missing file path")
			os.Exit(1)
		}

		inlineCSS(args[1])
	default:
		fmt.Println("Unexpected command: ", args[0])
		os.Exit(1)
	}
}

// parse and display CSS file
func parseCSS(filePath string) {
	input := readFile(filePath)

	stylesheet, err := parser.Parse(string(input))
	if err != nil {
		fmt.Println("Parsing error: ", err)
		os.Exit(1)
	}

	fmt.Println(stylesheet.String())
}

// inlines CSS into HTML and display result
func inlineCSS(filePath string) {
	input := readFile(filePath)

	output, err := inliner.Inline(string(input))
	if err != nil {
		fmt.Println("Inlining error: ", err)
		os.Exit(1)
	}

	fmt.Println(output)
}

func readFile(filePath string) []byte {
	file, err := ioutil.ReadFile(filePath)
	if err != nil {
		fmt.Println("Failed to open file: ", filePath, err)
		os.Exit(1)
	}

	return file
}
<|endoftext|>


<commit_before>package dropboxclient

import (
	"fmt"
	"github.com/koofr/go-httpclient"
	"github.com/koofr/go-ioutils"
	"io"
	"net/http"
	"net/url"
	"strconv"
)

type Dropbox struct {
	ApiHTTPClient     *httpclient.HTTPClient
	ContentHTTPClient *httpclient.HTTPClient
}

func NewDropbox(authToken string) (dropbox *Dropbox) {
	apiBaseUrl, _ := url.Parse("https://api.dropbox.com")
	contentBaseUrl, _ := url.Parse("https://api-content.dropbox.com")

	apiHttpClient := httpclient.New()
	apiHttpClient.BaseURL = apiBaseUrl
	apiHttpClient.Headers.Set("Authorization", "Bearer "+authToken)

	contentHttpClient := httpclient.New()
	contentHttpClient.BaseURL = contentBaseUrl
	contentHttpClient.Headers.Set("Authorization", "Bearer "+authToken)

	return &Dropbox{
		ApiHTTPClient:     apiHttpClient,
		ContentHTTPClient: contentHttpClient,
	}
}

func (c *Dropbox) Metadata(path string) (info *DropboxFile, err error) {
	_, err = c.ApiHTTPClient.Request(&httpclient.RequestData{
		Method:         "GET",
		Path:           "/1/metadata/auto/" + path,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &info,
	})

	if err != nil {
		return
	}

	return
}

func (c *Dropbox) Info(path string) (info *DropboxFile, err error) {
	res, err := c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "HEAD",
		Path:           "/1/files/auto/" + path,
		ExpectedStatus: []int{http.StatusOK},
		RespConsume:    true,
	})

	if err != nil {
		return
	}

	info = DropboxFileFromHeaders(path, res.Header)

	return
}

func (c *Dropbox) Get(path string, span *ioutils.FileSpan) (file *DropboxFile, err error) {
	req := httpclient.RequestData{
		Method:         "GET",
		Path:           "/1/files/auto/" + path,
		ExpectedStatus: []int{http.StatusOK, http.StatusPartialContent},
	}

	if span != nil {
		req.Headers = make(http.Header)
		req.Headers.Set("Range", fmt.Sprintf("bytes=%d-%d", span.Start, span.End))
	}

	res, err := c.ContentHTTPClient.Request(&req)

	if err != nil {
		return
	}

	file = DropboxFileFromHeaders(path, res.Header)
	file.Reader = res.Body

	return
}

func (c *Dropbox) ChunkedUpload(uploadId string, offset int64, reader io.Reader) (res *ChunkedUploadResult, err error) {
	params := make(url.Values)
	if uploadId != "" {
		params.Set("upload_id", uploadId)
	}
	if offset != 0 {
		params.Set("offset", strconv.FormatInt(offset, 10))
	}

	_, err = c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "PUT",
		Path:           "/1/chunked_upload",
		Params:         params,
		ReqReader:      reader,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &res,
	})

	return
}

func (c *Dropbox) CommitChunkedUpload(path string, uploadId string, overwrite bool) (res *CommitChunkedUploadResult, err error) {
	params := make(url.Values)
	params.Set("upload_id", uploadId)
	params.Set("overwrite", fmt.Sprintf("%t", overwrite))

	if overwrite {
		params.Set("autorename", "false")
	}

	_, err = c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "POST",
		Path:           "/1/commit_chunked_upload/auto/" + path,
		Params:         params,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &res,
	})

	return
}
<commit_msg>Added autorename parameter<commit_after>package dropboxclient

import (
	"fmt"
	"github.com/koofr/go-httpclient"
	"github.com/koofr/go-ioutils"
	"io"
	"net/http"
	"net/url"
	"strconv"
)

type Dropbox struct {
	ApiHTTPClient     *httpclient.HTTPClient
	ContentHTTPClient *httpclient.HTTPClient
}

func NewDropbox(authToken string) (dropbox *Dropbox) {
	apiBaseUrl, _ := url.Parse("https://api.dropbox.com")
	contentBaseUrl, _ := url.Parse("https://api-content.dropbox.com")

	apiHttpClient := httpclient.New()
	apiHttpClient.BaseURL = apiBaseUrl
	apiHttpClient.Headers.Set("Authorization", "Bearer "+authToken)

	contentHttpClient := httpclient.New()
	contentHttpClient.BaseURL = contentBaseUrl
	contentHttpClient.Headers.Set("Authorization", "Bearer "+authToken)

	return &Dropbox{
		ApiHTTPClient:     apiHttpClient,
		ContentHTTPClient: contentHttpClient,
	}
}

func (c *Dropbox) Metadata(path string) (info *DropboxFile, err error) {
	_, err = c.ApiHTTPClient.Request(&httpclient.RequestData{
		Method:         "GET",
		Path:           "/1/metadata/auto/" + path,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &info,
	})

	if err != nil {
		return
	}

	return
}

func (c *Dropbox) Info(path string) (info *DropboxFile, err error) {
	res, err := c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "HEAD",
		Path:           "/1/files/auto/" + path,
		ExpectedStatus: []int{http.StatusOK},
		RespConsume:    true,
	})

	if err != nil {
		return
	}

	info = DropboxFileFromHeaders(path, res.Header)

	return
}

func (c *Dropbox) Get(path string, span *ioutils.FileSpan) (file *DropboxFile, err error) {
	req := httpclient.RequestData{
		Method:         "GET",
		Path:           "/1/files/auto/" + path,
		ExpectedStatus: []int{http.StatusOK, http.StatusPartialContent},
	}

	if span != nil {
		req.Headers = make(http.Header)
		req.Headers.Set("Range", fmt.Sprintf("bytes=%d-%d", span.Start, span.End))
	}

	res, err := c.ContentHTTPClient.Request(&req)

	if err != nil {
		return
	}

	file = DropboxFileFromHeaders(path, res.Header)
	file.Reader = res.Body

	return
}

func (c *Dropbox) ChunkedUpload(uploadId string, offset int64, reader io.Reader) (res *ChunkedUploadResult, err error) {
	params := make(url.Values)
	if uploadId != "" {
		params.Set("upload_id", uploadId)
	}
	if offset != 0 {
		params.Set("offset", strconv.FormatInt(offset, 10))
	}

	_, err = c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "PUT",
		Path:           "/1/chunked_upload",
		Params:         params,
		ReqReader:      reader,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &res,
	})

	return
}

func (c *Dropbox) CommitChunkedUpload(path string, uploadId string, overwrite bool, autorename bool) (res *CommitChunkedUploadResult, err error) {
	params := make(url.Values)
	params.Set("upload_id", uploadId)
	params.Set("overwrite", fmt.Sprintf("%t", overwrite))
	params.Set("autorename", fmt.Sprintf("%t", autorename))

	_, err = c.ContentHTTPClient.Request(&httpclient.RequestData{
		Method:         "POST",
		Path:           "/1/commit_chunked_upload/auto/" + path,
		Params:         params,
		ExpectedStatus: []int{http.StatusOK},
		RespEncoding:   httpclient.EncodingJSON,
		RespValue:      &res,
	})

	return
}
<|endoftext|>


<commit_before>// Copyright 2016 yryz Author. All Rights Reserved.

package ds18b20

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

// Sensors get all connected sensor IDs as array
func Sensors() ([]string, error) {
	data, err := ioutil.ReadFile("/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves")
	if err != nil {
		return nil, err
	}

	sensors := strings.Split(string(data), "\n")
	if len(sensors) > 0 {
		sensors = sensors[:len(sensors)-1]
	}

	return sensors, nil
}

// Temperature get the temperature of a given sensor
func Temperature(sensor string) (float64, error) {
	data, err := ioutil.ReadFile("/sys/bus/w1/devices/" + sensor + "/w1_slave")
	if err != nil {
		return 0.0, nil
	}

	if strings.Contains(string(data), "YES") {
		arr := strings.SplitN(string(data), " ", 3)

		switch arr[1][0] {
		case 'f': //-0.5 ~ -55°C
			x, err := strconv.ParseInt(arr[1]+arr[0], 16, 32)
			if err != nil {
				return 0.0, err
			}
			return float64(^x+1) * 0.0625, nil

		case '0': //0~125°C
			x, err := strconv.ParseInt(arr[1]+arr[0], 16, 32)
			if err != nil {
				return 0.0, err
			}
			return float64(x) * 0.0625, nil
		}
	}

	return 0.0, errors.New("can not read temperature for sensor " + sensor)
}
<commit_msg>Fix possible problems with zero degrees Celsius. #1<commit_after>// Copyright 2016 yryz Author. All Rights Reserved.

package ds18b20

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

var ErrReadSensor = errors.New("failed to read sensor temperature")

// Sensors get all connected sensor IDs as array
func Sensors() ([]string, error) {
	data, err := ioutil.ReadFile("/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves")
	if err != nil {
		return nil, err
	}

	sensors := strings.Split(string(data), "\n")
	if len(sensors) > 0 {
		sensors = sensors[:len(sensors)-1]
	}

	return sensors, nil
}

// Temperature get the temperature of a given sensor
func Temperature(sensor string) (float64, error) {
	data, err := ioutil.ReadFile("/sys/bus/w1/devices/" + sensor + "/w1_slave")
	if err != nil {
		return 0.0, ErrReadSensor
	}

	raw := string(data)

	i := strings.LastIndex(raw, "t=")
	if i == -1 {
		return 0.0, ErrReadSensor
	}

	c, err := strconv.ParseFloat(raw[i+2:len(raw)-1], 64)
	if err != nil {
		return 0.0, ErrReadSensor
	}

	return c / 1000.0, nil
}
<|endoftext|>


<commit_before>package dsmr4p1

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/howeyc/crc16"
)

// Compute and return the CRC16 checksum over the byte slice in data.
// According to the DSMR 4.0.4 spec, this CRC16 uses the polynomial
// x^16 + x^15 + x^2 + 1, which is the same polynomial as in CRC16-IBM.
// However, we cannot simply use the checksum of the crc16 package as this version
// of the spec (as opposed to the 4.0 version) also states: "CRC16 uses no XOR in,
// no XOR out and is computed with least significant bit first." This code is the same
// as the "update" function in the crc16 function minus the initial and final XOR operations.
func p1crc16(data []byte) (crc uint16) {
	crc = 0
	for _, v := range data {
		crc = crc16.IBMTable[byte(crc)^v] ^ (crc >> 8)
	}
	return
}

// Constants for now as I'm assuming all dutch smartmeters will be in the
// same Dutch timezone.
const (
	summerTimezone = "CEST"
	winterTimezone = "CET"
)

// Parse the timestamp format used in the dutch smartmeters. Do note this function
// assumes the CET/CEST timezone.
func ParseTimestamp(timestamp string) (time.Time, error) {
	// The format for the timestamp is:
	// YYMMDDhhmmssX
	// The value used for X determines whether DST is active.
	// S (summer?) means yes, W (winter?) means no.

	var timezone string
	switch timestamp[len(timestamp)-1] {
	case 'S':
		timezone = summerTimezone
	case 'W':
		timezone = winterTimezone
	default:
		return time.Time{}, errors.New("Error parsing timestamp: missing DST indicator")
	}

	// To make sure parsing is always consistent and indepentent of the
	// the local timezone of the host this code is running on, let's for now
	// assume Dutch time.
	loc, err := time.LoadLocation("Europe/Amsterdam")

	timestamp = timestamp[:len(timestamp)-1] + " " + timezone
	ts, err := time.ParseInLocation("060102150405 MST", timestamp, loc)
	if err != nil {
		return ts, err
	}
	return ts, nil
}

// Starts polling and attempts to parse a telegram.
func startPolling(input io.Reader, ch chan Telegram) {
	br := bufio.NewReader(input)
	for {
		// Read until we find a '/', which should be the beginning of the telegram.
		_, err := br.ReadBytes('/')
		if err == io.EOF {
			break
		} else if err != nil {
			log.Println(err)
			continue
		}

		// Unread the byte as the '/' is also part of the CRC computation.
		err = br.UnreadByte()
		if err != nil {
			log.Println(err)
			continue
		}

		// The '!' character signals the end of the telegram.
		data, err := br.ReadBytes('!')
		if err != nil {
			log.Println(err)
			continue
		}
		// The four hexadecimal characters are the CRC-16 of the preceding data, delimitted by
		// a carriage return.
		crcBytes, err := br.ReadBytes('\n')
		if err != nil {
			log.Println(err)
			continue
		}

		if len(crcBytes) != 6 {
			log.Println("Unexpected number of CRC bytes.")
			continue // Maybe we can recover?
		}
		dataCRC := string(crcBytes[:4])
		computedCRC := fmt.Sprintf("%04X", p1crc16(data))

		if dataCRC == computedCRC {
			t := Telegram(data)
			ch <- t
		} else {
			log.Printf("CRC values do not match: %s vs %s\n", dataCRC, computedCRC)
		}
	}
	// Close the channel (should only happen with EOF, allows for clean exit).
	close(ch)
}

// Start polling the P1 port. This function will start a goroutine and received telegrams are
// put into returned channel. Only telegrams whose CRC value are correct are put into
// the channel.
func Poll(input io.Reader) chan Telegram {
	ch := make(chan Telegram)
	go startPolling(input, ch)
	return ch
}

// Some code to simulate a smartmeter
type delayedReader struct {
	rd     *bufio.Reader
	delim  byte
	ticker *time.Ticker
}

func (dr *delayedReader) Read(p []byte) (n int, err error) {
	tmp, _ := dr.rd.Peek(len(p))
	i1 := bytes.IndexByte(tmp, dr.delim)
	// No start of telegram here, just continue reading
	if i1 == -1 {
		n, err = dr.rd.Read(p)
		return
	}
	// So there is a '/' coming up. If the '/' is not the first charactar, simply let read
	// until it is.
	if i1 != 0 {
		n, err = dr.rd.Read(p[:i1])
		return
	}

	// i1 == 0, so tmp[0] == '/': a new telegram is coming up. Let's wait until the ticker fires.
	<-dr.ticker.C

	// Ok, but how much should we return? Is there maybe another '/'?
	i2 := bytes.IndexByte(tmp[i1+1:], dr.delim)

	// If there isn't, just read the rest.
	if i2 == -1 {
		n, err = dr.rd.Read(p)
		return
	}

	// Finally, if there is another '/' coming up, read until that character.
	n, err = dr.rd.Read(p[:i2])
	return
}

// Take a io.Reader (typically the output of a os.Open) and delay the output of each Telegram
// (delimited by a '/') at a certain rate (delay). The main purpose is for testing/simulation. Simply
// save the  output of an actual smartmeter to a file. Then in your test program open the file and
// use the resulting io.Reader with this function. The resulting io.Reader will mimick a real smart-meter
// that outputs a telegram every n seconds (typically 10).
func RateLimit(input io.Reader, delay time.Duration) io.Reader {
	return &delayedReader{rd: bufio.NewReader(input), delim: '/', ticker: time.NewTicker(delay)}
}
<commit_msg>Add package description.<commit_after>// Go library for reading (and parsing) data from the P1 port of dutch smart meters.
package dsmr4p1

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/howeyc/crc16"
)

// Compute and return the CRC16 checksum over the byte slice in data.
// According to the DSMR 4.0.4 spec, this CRC16 uses the polynomial
// x^16 + x^15 + x^2 + 1, which is the same polynomial as in CRC16-IBM.
// However, we cannot simply use the checksum of the crc16 package as this version
// of the spec (as opposed to the 4.0 version) also states: "CRC16 uses no XOR in,
// no XOR out and is computed with least significant bit first." This code is the same
// as the "update" function in the crc16 function minus the initial and final XOR operations.
func p1crc16(data []byte) (crc uint16) {
	crc = 0
	for _, v := range data {
		crc = crc16.IBMTable[byte(crc)^v] ^ (crc >> 8)
	}
	return
}

// Constants for now as I'm assuming all dutch smartmeters will be in the
// same Dutch timezone.
const (
	summerTimezone = "CEST"
	winterTimezone = "CET"
)

// Parse the timestamp format used in the dutch smartmeters. Do note this function
// assumes the CET/CEST timezone.
func ParseTimestamp(timestamp string) (time.Time, error) {
	// The format for the timestamp is:
	// YYMMDDhhmmssX
	// The value used for X determines whether DST is active.
	// S (summer?) means yes, W (winter?) means no.

	var timezone string
	switch timestamp[len(timestamp)-1] {
	case 'S':
		timezone = summerTimezone
	case 'W':
		timezone = winterTimezone
	default:
		return time.Time{}, errors.New("Error parsing timestamp: missing DST indicator")
	}

	// To make sure parsing is always consistent and indepentent of the
	// the local timezone of the host this code is running on, let's for now
	// assume Dutch time.
	loc, err := time.LoadLocation("Europe/Amsterdam")

	timestamp = timestamp[:len(timestamp)-1] + " " + timezone
	ts, err := time.ParseInLocation("060102150405 MST", timestamp, loc)
	if err != nil {
		return ts, err
	}
	return ts, nil
}

// Starts polling and attempts to parse a telegram.
func startPolling(input io.Reader, ch chan Telegram) {
	br := bufio.NewReader(input)
	for {
		// Read until we find a '/', which should be the beginning of the telegram.
		_, err := br.ReadBytes('/')
		if err == io.EOF {
			break
		} else if err != nil {
			log.Println(err)
			continue
		}

		// Unread the byte as the '/' is also part of the CRC computation.
		err = br.UnreadByte()
		if err != nil {
			log.Println(err)
			continue
		}

		// The '!' character signals the end of the telegram.
		data, err := br.ReadBytes('!')
		if err != nil {
			log.Println(err)
			continue
		}
		// The four hexadecimal characters are the CRC-16 of the preceding data, delimitted by
		// a carriage return.
		crcBytes, err := br.ReadBytes('\n')
		if err != nil {
			log.Println(err)
			continue
		}

		if len(crcBytes) != 6 {
			log.Println("Unexpected number of CRC bytes.")
			continue // Maybe we can recover?
		}
		dataCRC := string(crcBytes[:4])
		computedCRC := fmt.Sprintf("%04X", p1crc16(data))

		if dataCRC == computedCRC {
			t := Telegram(data)
			ch <- t
		} else {
			log.Printf("CRC values do not match: %s vs %s\n", dataCRC, computedCRC)
		}
	}
	// Close the channel (should only happen with EOF, allows for clean exit).
	close(ch)
}

// Start polling the P1 port. This function will start a goroutine and received telegrams are
// put into returned channel. Only telegrams whose CRC value are correct are put into
// the channel.
func Poll(input io.Reader) chan Telegram {
	ch := make(chan Telegram)
	go startPolling(input, ch)
	return ch
}

// Some code to simulate a smartmeter
type delayedReader struct {
	rd     *bufio.Reader
	delim  byte
	ticker *time.Ticker
}

func (dr *delayedReader) Read(p []byte) (n int, err error) {
	tmp, _ := dr.rd.Peek(len(p))
	i1 := bytes.IndexByte(tmp, dr.delim)
	// No start of telegram here, just continue reading
	if i1 == -1 {
		n, err = dr.rd.Read(p)
		return
	}
	// So there is a '/' coming up. If the '/' is not the first charactar, simply let read
	// until it is.
	if i1 != 0 {
		n, err = dr.rd.Read(p[:i1])
		return
	}

	// i1 == 0, so tmp[0] == '/': a new telegram is coming up. Let's wait until the ticker fires.
	<-dr.ticker.C

	// Ok, but how much should we return? Is there maybe another '/'?
	i2 := bytes.IndexByte(tmp[i1+1:], dr.delim)

	// If there isn't, just read the rest.
	if i2 == -1 {
		n, err = dr.rd.Read(p)
		return
	}

	// Finally, if there is another '/' coming up, read until that character.
	n, err = dr.rd.Read(p[:i2])
	return
}

// Take a io.Reader (typically the output of a os.Open) and delay the output of each Telegram
// (delimited by a '/') at a certain rate (delay). The main purpose is for testing/simulation. Simply
// save the  output of an actual smartmeter to a file. Then in your test program open the file and
// use the resulting io.Reader with this function. The resulting io.Reader will mimick a real smart-meter
// that outputs a telegram every n seconds (typically 10).
func RateLimit(input io.Reader, delay time.Duration) io.Reader {
	return &delayedReader{rd: bufio.NewReader(input), delim: '/', ticker: time.NewTicker(delay)}
}
<|endoftext|>


<commit_before>/*
 * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package minio

import "time"

// BucketInfo container for bucket metadata.
type BucketInfo struct {
	// The name of the bucket.
	Name string `json:"name"`
	// Date the bucket was created.
	CreationDate time.Time `json:"creation_date"`
}

// ObjectInfo container for object metadata.
type ObjectInfo struct {
	// An ETag is optionally set to md5sum of an object.  In case of multipart objects,
	// ETag is of the form MD5SUM-N where MD5SUM is md5sum of all individual md5sums of
	// each parts concatenated into one string.
	ETag string

	Key          string    // Name of the object
	LastModified time.Time // Date and time the object was last modified.
	Size         int64     // Size in bytes of the object.
	ContentType  string    // A standard MIME type describing the format of the object data.

	// Owner name.
	Owner struct {
		DisplayName string
		ID          string
	}

	// The class of storage used to store the object.
	StorageClass string

	// Error
	Err error
}

// ObjectMultipartInfo container for multipart object metadata.
type ObjectMultipartInfo struct {
	// Date and time at which the multipart upload was initiated.
	Initiated time.Time `type:"timestamp" timestampFormat:"iso8601"`

	Initiator initiator
	Owner     owner

	// The type of storage to use for the object. Defaults to 'STANDARD'.
	StorageClass string

	// Key of the object for which the multipart upload was initiated.
	Key string

	// Size in bytes of the object.
	Size int64

	// Upload ID that identifies the multipart upload.
	UploadID string `xml:"UploadId"`

	// Error
	Err error
}
<commit_msg>annotate ObjectInfo to JSON-aware<commit_after>/*
 * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package minio

import "time"

// BucketInfo container for bucket metadata.
type BucketInfo struct {
	// The name of the bucket.
	Name string `json:"name"`
	// Date the bucket was created.
	CreationDate time.Time `json:"creationDate"`
}

// ObjectInfo container for object metadata.
type ObjectInfo struct {
	// An ETag is optionally set to md5sum of an object.  In case of multipart objects,
	// ETag is of the form MD5SUM-N where MD5SUM is md5sum of all individual md5sums of
	// each parts concatenated into one string.
	ETag string `json:"etag"`

	Key          string `json:"name"`            // Name of the object
	LastModified time.Time `json:"lastModified"` // Date and time the object was last modified.
	Size         int64 `json:"size"`             // Size in bytes of the object.
	ContentType  string `json:"contentType"`     // A standard MIME type describing the format of the object data.

	// Owner name.
	Owner struct {
		DisplayName string `json:"name"`
		ID          string `json:"id"`
	} `json:"owner"`

	// The class of storage used to store the object.
	StorageClass string `json:"storageClass"`

	// Error
	Err error `json:"-"`
}

// ObjectMultipartInfo container for multipart object metadata.
type ObjectMultipartInfo struct {
	// Date and time at which the multipart upload was initiated.
	Initiated time.Time `type:"timestamp" timestampFormat:"iso8601"`

	Initiator initiator
	Owner     owner

	// The type of storage to use for the object. Defaults to 'STANDARD'.
	StorageClass string

	// Key of the object for which the multipart upload was initiated.
	Key string

	// Size in bytes of the object.
	Size int64

	// Upload ID that identifies the multipart upload.
	UploadID string `xml:"UploadId"`

	// Error
	Err error
}
<|endoftext|>


<commit_before><commit_msg>Add remove func<commit_after><|endoftext|>


<commit_before>package pwr

import (
	"context"
	"io"
	"sync"

	"github.com/itchio/lake"
	"github.com/itchio/savior"
	"github.com/pkg/errors"
)

type SafeKeeperOpen func() (savior.SeekSource, error)

type fileBlocks = map[int]error

type safeKeeper struct {
	inner lake.Pool

	open SafeKeeperOpen

	sigLock  sync.Mutex
	sigInfo  *SignatureInfo
	sigError error

	validBlocks map[int64]fileBlocks
}

var _ lake.Pool = (*safeKeeper)(nil)

type SafeKeeperParams struct {
	Inner lake.Pool
	Open  SafeKeeperOpen
}

func NewSafeKeeper(params SafeKeeperParams) (lake.Pool, error) {
	if params.Inner == nil {
		return nil, errors.New("SafeKeeperParams.Inner can't be nil")
	}
	if params.Open == nil {
		return nil, errors.New("SafeKeeperParams.Open can't be nil")
	}

	sk := &safeKeeper{
		inner: params.Inner,
		open:  params.Open,
	}
	return sk, nil
}

func (sk *safeKeeper) GetSize(fileIndex int64) int64 {
	return sk.inner.GetSize(fileIndex)
}

func (sk *safeKeeper) GetReadSeeker(fileIndex int64) (io.ReadSeeker, error) {
	rs, err := sk.inner.GetReadSeeker(fileIndex)
	if err != nil {
		return nil, err
	}

	res := &safeKeeperReader{
		sk:        sk,
		rs:        rs,
		fileIndex: fileIndex,
	}
	return res, nil
}

func (sk *safeKeeper) GetReader(fileIndex int64) (io.Reader, error) {
	return sk.GetReadSeeker(fileIndex)
}

func (sk *safeKeeper) Close() error {
	return sk.inner.Close()
}

func (sk *safeKeeper) getSignature() (*SignatureInfo, error) {
	sk.sigLock.Lock()
	defer sk.sigLock.Unlock()

	if sk.sigInfo != nil {
		return sk.sigInfo, nil
	}

	if sk.sigError != nil {
		return nil, sk.sigError
	}

	source, err := sk.open()
	if err != nil {
		// store error so we don't keep retrying to open
		// note that eos has built-in retry logic, so we're fine.
		sk.sigError = err
		return nil, err
	}

	// this seems bad, because it could hang forever, but
	// *hopefully* all our "network file" timeouts are set up
	// correctly so it doesn't.
	ctx := context.Background()

	sigInfo, err := ReadSignature(ctx, source)
	if err != nil {
		sk.sigError = err
		return nil, err
	}

	sk.sigInfo = sigInfo
	return sk.sigInfo, nil
}

type safeKeeperReader struct {
	// specified
	rs        io.ReadSeeker
	sk        *safeKeeper
	fileIndex int64

	// internal
	offset      int64
}

var _ io.ReadSeeker = (*safeKeeperReader)(nil)

func (skr *safeKeeperReader) Seek(off int64, whence int) (int64, error) {
	offset, err := skr.rs.Seek(off, whence)
	skr.offset = offset
	return offset, err
}

func (skr *safeKeeperReader) Read(p []byte) (int, error) {
	blockNumber := skr.offset / BlockSize
	if valid, done := skr.validBlocks[blockblockNumber] {

	}

	sig, err := skr.sk.getSignature()
	if err != nil {
		return 0, err
	}

	// TODO: check hashes
	n, err := skr.rs.Read(p)
	skr.offset += int64(n)
	return n, err
}
<commit_msg>wip safekeeper<commit_after>package pwr

import (
	"context"
	"io"
	"sync"

	"github.com/itchio/lake"
	"github.com/itchio/savior"
	"github.com/pkg/errors"
)

type SafeKeeperOpen func() (savior.SeekSource, error)

type fileBlocks = map[int]error

type safeKeeper struct {
	inner lake.Pool

	open SafeKeeperOpen

	sigLock  sync.Mutex
	sigInfo  *SignatureInfo
	sigError error

	validBlocks map[int64]fileBlocks
}

var _ lake.Pool = (*safeKeeper)(nil)

type SafeKeeperParams struct {
	Inner lake.Pool
	Open  SafeKeeperOpen
}

func NewSafeKeeper(params SafeKeeperParams) (lake.Pool, error) {
	if params.Inner == nil {
		return nil, errors.New("SafeKeeperParams.Inner can't be nil")
	}
	if params.Open == nil {
		return nil, errors.New("SafeKeeperParams.Open can't be nil")
	}

	sk := &safeKeeper{
		inner: params.Inner,
		open:  params.Open,
	}
	return sk, nil
}

func (sk *safeKeeper) GetSize(fileIndex int64) int64 {
	return sk.inner.GetSize(fileIndex)
}

func (sk *safeKeeper) GetReadSeeker(fileIndex int64) (io.ReadSeeker, error) {
	rs, err := sk.inner.GetReadSeeker(fileIndex)
	if err != nil {
		return nil, err
	}

	res := &safeKeeperReader{
		sk:        sk,
		rs:        rs,
		fileIndex: fileIndex,
	}
	return res, nil
}

func (sk *safeKeeper) GetReader(fileIndex int64) (io.Reader, error) {
	return sk.GetReadSeeker(fileIndex)
}

func (sk *safeKeeper) Close() error {
	return sk.inner.Close()
}

func (sk *safeKeeper) getSignature() (*SignatureInfo, error) {
	sk.sigLock.Lock()
	defer sk.sigLock.Unlock()

	if sk.sigInfo != nil {
		return sk.sigInfo, nil
	}

	if sk.sigError != nil {
		return nil, sk.sigError
	}

	source, err := sk.open()
	if err != nil {
		// store error so we don't keep retrying to open
		// note that eos has built-in retry logic, so we're fine.
		sk.sigError = err
		return nil, err
	}

	// this seems bad, because it could hang forever, but
	// *hopefully* all our "network file" timeouts are set up
	// correctly so it doesn't.
	ctx := context.Background()

	sigInfo, err := ReadSignature(ctx, source)
	if err != nil {
		sk.sigError = err
		return nil, err
	}

	sk.sigInfo = sigInfo
	return sk.sigInfo, nil
}

func (sk *safeKeeper) validateBlock(fileIndex int64, offset int64) error {
	blockNumber := skr.offset / BlockSize
	if valid, done := skr.validBlocks[blockblockNumber]; ok {

	}

	sig, err := skr.sk.getSignature()
	if err != nil {
		return 0, err
	}
}

type safeKeeperReader struct {
	// specified
	rs        io.ReadSeeker
	sk        *safeKeeper
	fileIndex int64

	// internal
	offset int64
}

var _ io.ReadSeeker = (*safeKeeperReader)(nil)

func (skr *safeKeeperReader) Seek(off int64, whence int) (int64, error) {
	offset, err := skr.rs.Seek(off, whence)
	skr.offset = offset
	return offset, err
}

func (skr *safeKeeperReader) Read(p []byte) (int, error) {
	err := skr.sr.validateBlock(skr.fileIndex, skr.rs, skr.offset)
	if err != nil {
		return 0, err
	}

	// TODO: check hashes
	n, err := skr.rs.Read(p)
	skr.offset += int64(n)
	return n, err
}
<|endoftext|>


<commit_before>package pgo_cli_test

/*
 Copyright 2020 Crunchy Data Solutions, Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

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

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

import (
	"regexp"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

// TC41 ✓
func TestClusterCreate(t *testing.T) {
	t.Parallel()

	withNamespace(t, func(namespace func() string) {
		t.Run("create cluster", func(t *testing.T) {
			t.Run("creates a workflow", func(t *testing.T) {
				output, err := pgo("create", "cluster", "mycluster", "-n", namespace()).Exec(t)
				defer teardownCluster(t, namespace(), "mycluster", time.Now())
				require.NoError(t, err)
				require.Contains(t, output, "workflow id")

				workflow := regexp.MustCompile(`\S+$`).FindString(strings.TrimSpace(output))
				require.NotEmpty(t, workflow)

				_, err = pgo("show", "workflow", workflow, "-n", namespace()).Exec(t)
				require.NoError(t, err)
			})
		})

		withCluster(t, namespace, func(cluster func() string) {
			t.Run("show cluster", func(t *testing.T) {
				t.Run("shows something", func(t *testing.T) {
					output, err := pgo("show", "cluster", cluster(), "-n", namespace()).Exec(t)
					require.NoError(t, err)
					require.NotEmpty(t, output)
				})
			})

			t.Run("show user", func(t *testing.T) {
				t.Run("shows something", func(t *testing.T) {
					output, err := pgo("show", "user", cluster(), "-n", namespace()).Exec(t)
					require.NoError(t, err)
					require.NotEmpty(t, output)
				})
			})
		})
	})
}
<commit_msg>Check for workflow id more specifically in tests<commit_after>package pgo_cli_test

/*
 Copyright 2020 Crunchy Data Solutions, Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

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

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

import (
	"regexp"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

// TC41 ✓
func TestClusterCreate(t *testing.T) {
	t.Parallel()

	withNamespace(t, func(namespace func() string) {
		t.Run("create cluster", func(t *testing.T) {
			t.Run("creates a workflow", func(t *testing.T) {
				workflow := regexp.MustCompile(`(?m:^workflow id.*?(\S+)$)`)

				output, err := pgo("create", "cluster", "mycluster", "-n", namespace()).Exec(t)
				defer teardownCluster(t, namespace(), "mycluster", time.Now())
				require.NoError(t, err)
				require.Regexp(t, workflow, output, "expected pgo to show the workflow")

				_, err = pgo("show", "workflow", workflow.FindStringSubmatch(output)[1], "-n", namespace()).Exec(t)
				require.NoError(t, err)
			})
		})

		withCluster(t, namespace, func(cluster func() string) {
			t.Run("show cluster", func(t *testing.T) {
				t.Run("shows something", func(t *testing.T) {
					output, err := pgo("show", "cluster", cluster(), "-n", namespace()).Exec(t)
					require.NoError(t, err)
					require.NotEmpty(t, output)
				})
			})

			t.Run("show user", func(t *testing.T) {
				t.Run("shows something", func(t *testing.T) {
					output, err := pgo("show", "user", cluster(), "-n", namespace()).Exec(t)
					require.NoError(t, err)
					require.NotEmpty(t, output)
				})
			})
		})
	})
}
<|endoftext|>


<commit_before>package testutils

import (
	"errors"
	"time"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/controller/utils"
	"github.com/flynn/flynn/pkg/stream"
)

type FakeControllerClient struct {
	releases         map[string]*ct.Release
	artifacts        map[string]*ct.Artifact
	formations       map[string]map[string]*ct.Formation
	formationStreams map[chan<- *ct.ExpandedFormation]struct{}
	jobs             map[string]*ct.Job
	apps             map[string]*ct.App
}

func NewFakeControllerClient() *FakeControllerClient {
	return &FakeControllerClient{
		releases:         make(map[string]*ct.Release),
		artifacts:        make(map[string]*ct.Artifact),
		formations:       make(map[string]map[string]*ct.Formation),
		formationStreams: make(map[chan<- *ct.ExpandedFormation]struct{}),
		apps:             make(map[string]*ct.App),
		jobs:             make(map[string]*ct.Job),
	}
}

func (c *FakeControllerClient) GetRelease(releaseID string) (*ct.Release, error) {
	if release, ok := c.releases[releaseID]; ok {
		return release, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetArtifact(artifactID string) (*ct.Artifact, error) {
	if artifact, ok := c.artifacts[artifactID]; ok {
		return artifact, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetFormation(appID, releaseID string) (*ct.Formation, error) {
	if releases, ok := c.formations[appID]; ok {
		if formation, ok := releases[releaseID]; ok {
			return formation, nil
		}
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetExpandedFormation(appID, releaseID string) (*ct.ExpandedFormation, error) {
	app, ok := c.apps[appID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	release, ok := c.releases[releaseID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	releases, ok := c.formations[appID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	formation, ok := releases[releaseID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	procs := make(map[string]int, len(formation.Processes))
	for typ, n := range formation.Processes {
		procs[typ] = n
	}
	return &ct.ExpandedFormation{
		App:           app,
		Release:       release,
		ImageArtifact: c.artifacts[release.ImageArtifactID()],
		Processes:     procs,
	}, nil
}

func (c *FakeControllerClient) GetApp(appID string) (*ct.App, error) {
	if app, ok := c.apps[appID]; ok {
		return app, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) CreateApp(app *ct.App) error {
	c.apps[app.ID] = app
	return nil
}

func (c *FakeControllerClient) CreateRelease(release *ct.Release) error {
	c.releases[release.ID] = release
	return nil
}

func (c *FakeControllerClient) CreateArtifact(artifact *ct.Artifact) error {
	c.artifacts[artifact.ID] = artifact
	return nil
}

func (c *FakeControllerClient) PutFormation(formation *ct.Formation) error {
	releases, ok := c.formations[formation.AppID]
	if !ok {
		releases = make(map[string]*ct.Formation)
		c.formations[formation.AppID] = releases
	}
	releases[formation.ReleaseID] = formation

	for ch := range c.formationStreams {
		ef, err := utils.ExpandFormation(c, formation)
		if err == nil {
			ch <- ef
		}
	}

	return nil
}

func (c *FakeControllerClient) AppList() ([]*ct.App, error) {
	apps := make([]*ct.App, 0, len(c.apps))
	for _, app := range c.apps {
		apps = append(apps, app)
	}
	return apps, nil
}

func (c *FakeControllerClient) FormationListActive() ([]*ct.ExpandedFormation, error) {
	var formations []*ct.ExpandedFormation
	for appID, releases := range c.formations {
		app, ok := c.apps[appID]
		if !ok {
			continue
		}
		for releaseID, formation := range releases {
			count := 0
			procs := make(map[string]int, len(formation.Processes))
			for typ, n := range formation.Processes {
				count += n
				procs[typ] = n
			}
			if count == 0 {
				continue
			}
			release, ok := c.releases[releaseID]
			if !ok {
				continue
			}
			artifact := c.artifacts[release.ImageArtifactID()]
			formations = append(formations, &ct.ExpandedFormation{
				App:           app,
				Release:       release,
				ImageArtifact: artifact,
				Processes:     procs,
			})
		}
	}
	return formations, nil
}

func (c *FakeControllerClient) StreamFormations(since *time.Time, ch chan<- *ct.ExpandedFormation) (stream.Stream, error) {
	if _, ok := c.formationStreams[ch]; ok {
		return nil, errors.New("Already streaming to that channel")
	}

	for _, releases := range c.formations {
		for _, f := range releases {
			ef, err := utils.ExpandFormation(c, f)
			if err == nil {
				ch <- ef
			}
		}
	}
	ch <- &ct.ExpandedFormation{}

	c.formationStreams[ch] = struct{}{}
	return &FormationStream{
		cc: c,
		ch: ch,
	}, nil
}

func (c *FakeControllerClient) PutJob(job *ct.Job) error {
	c.jobs[job.ID] = job
	return nil
}

func (c *FakeControllerClient) JobListActive() ([]*ct.Job, error) {
	list := make([]*ct.Job, 0, len(c.jobs))
	for _, job := range c.jobs {
		if job.State == ct.JobStateStarting || job.State == ct.JobStateUp {
			list = append(list, job)
		}
	}
	return list, nil
}

func NewRelease(id string, artifact *ct.Artifact, processes map[string]int) *ct.Release {
	return NewReleaseOmni(id, artifact, processes, false)
}

func NewReleaseOmni(id string, artifact *ct.Artifact, processes map[string]int, omni bool) *ct.Release {
	processTypes := make(map[string]ct.ProcessType, len(processes))
	for t := range processes {
		processTypes[t] = ct.ProcessType{
			Cmd:  []string{"start", t},
			Omni: omni,
		}
	}

	return &ct.Release{
		ID:          id,
		ArtifactIDs: []string{artifact.ID},
		Processes:   processTypes,
	}
}

type FormationStream struct {
	cc *FakeControllerClient
	ch chan<- *ct.ExpandedFormation
}

func (fs *FormationStream) Close() error {
	delete(fs.cc.formationStreams, fs.ch)
	close(fs.ch)
	return nil
}

func (fs *FormationStream) Err() error {
	return nil
}
<commit_msg>controller/testutils: Wrap controller client structures in a mutex<commit_after>package testutils

import (
	"errors"
	"sync"
	"time"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/controller/utils"
	"github.com/flynn/flynn/pkg/stream"
)

type FakeControllerClient struct {
	releases         map[string]*ct.Release
	artifacts        map[string]*ct.Artifact
	formations       map[string]map[string]*ct.Formation
	formationStreams map[chan<- *ct.ExpandedFormation]struct{}
	jobs             map[string]*ct.Job
	apps             map[string]*ct.App
	mtx              sync.Mutex
}

func NewFakeControllerClient() *FakeControllerClient {
	return &FakeControllerClient{
		releases:         make(map[string]*ct.Release),
		artifacts:        make(map[string]*ct.Artifact),
		formations:       make(map[string]map[string]*ct.Formation),
		formationStreams: make(map[chan<- *ct.ExpandedFormation]struct{}),
		apps:             make(map[string]*ct.App),
		jobs:             make(map[string]*ct.Job),
	}
}

func (c *FakeControllerClient) GetRelease(releaseID string) (*ct.Release, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	if release, ok := c.releases[releaseID]; ok {
		return release, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetArtifact(artifactID string) (*ct.Artifact, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	if artifact, ok := c.artifacts[artifactID]; ok {
		return artifact, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetFormation(appID, releaseID string) (*ct.Formation, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	if releases, ok := c.formations[appID]; ok {
		if formation, ok := releases[releaseID]; ok {
			return formation, nil
		}
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) GetExpandedFormation(appID, releaseID string) (*ct.ExpandedFormation, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	return c.getExpandedFormation(appID, releaseID)
}

func (c *FakeControllerClient) getExpandedFormation(appID, releaseID string) (*ct.ExpandedFormation, error) {
	app, ok := c.apps[appID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	release, ok := c.releases[releaseID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	releases, ok := c.formations[appID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	formation, ok := releases[releaseID]
	if !ok {
		return nil, controller.ErrNotFound
	}
	procs := make(map[string]int, len(formation.Processes))
	for typ, n := range formation.Processes {
		procs[typ] = n
	}
	return &ct.ExpandedFormation{
		App:           app,
		Release:       release,
		ImageArtifact: c.artifacts[release.ImageArtifactID()],
		Processes:     procs,
	}, nil
}

func (c *FakeControllerClient) GetApp(appID string) (*ct.App, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	if app, ok := c.apps[appID]; ok {
		return app, nil
	}
	return nil, controller.ErrNotFound
}

func (c *FakeControllerClient) CreateApp(app *ct.App) error {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	c.apps[app.ID] = app
	return nil
}

func (c *FakeControllerClient) CreateRelease(release *ct.Release) error {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	c.releases[release.ID] = release
	return nil
}

func (c *FakeControllerClient) CreateArtifact(artifact *ct.Artifact) error {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	c.artifacts[artifact.ID] = artifact
	return nil
}

func (c *FakeControllerClient) PutFormation(formation *ct.Formation) error {
	c.mtx.Lock()

	releases, ok := c.formations[formation.AppID]
	if !ok {
		releases = make(map[string]*ct.Formation)
		c.formations[formation.AppID] = releases
	}
	releases[formation.ReleaseID] = formation

	streams := make([]chan<- *ct.ExpandedFormation, 0, len(c.formationStreams))
	for ch := range c.formationStreams {
		streams = append(streams, ch)
	}

	c.mtx.Unlock()

	for _, ch := range streams {
		ef, err := utils.ExpandFormation(c, formation)
		if err == nil {
			ch <- ef
		}
	}

	return nil
}

func (c *FakeControllerClient) AppList() ([]*ct.App, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	apps := make([]*ct.App, 0, len(c.apps))
	for _, app := range c.apps {
		apps = append(apps, app)
	}
	return apps, nil
}

func (c *FakeControllerClient) FormationListActive() ([]*ct.ExpandedFormation, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	var formations []*ct.ExpandedFormation
	for appID, releases := range c.formations {
		app, ok := c.apps[appID]
		if !ok {
			continue
		}
		for releaseID, formation := range releases {
			count := 0
			procs := make(map[string]int, len(formation.Processes))
			for typ, n := range formation.Processes {
				count += n
				procs[typ] = n
			}
			if count == 0 {
				continue
			}
			release, ok := c.releases[releaseID]
			if !ok {
				continue
			}
			artifact := c.artifacts[release.ImageArtifactID()]
			formations = append(formations, &ct.ExpandedFormation{
				App:           app,
				Release:       release,
				ImageArtifact: artifact,
				Processes:     procs,
			})
		}
	}
	return formations, nil
}

func (c *FakeControllerClient) StreamFormations(since *time.Time, ch chan<- *ct.ExpandedFormation) (stream.Stream, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if _, ok := c.formationStreams[ch]; ok {
		return nil, errors.New("Already streaming to that channel")
	}

	for _, releases := range c.formations {
		for _, f := range releases {
			ef, err := c.getExpandedFormation(f.AppID, f.ReleaseID)
			if err == nil {
				ch <- ef
			}
		}
	}
	ch <- &ct.ExpandedFormation{}

	c.formationStreams[ch] = struct{}{}
	return &FormationStream{
		cc: c,
		ch: ch,
	}, nil
}

func (c *FakeControllerClient) PutJob(job *ct.Job) error {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	c.jobs[job.ID] = job
	return nil
}

func (c *FakeControllerClient) JobListActive() ([]*ct.Job, error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()

	list := make([]*ct.Job, 0, len(c.jobs))
	for _, job := range c.jobs {
		if job.State == ct.JobStateStarting || job.State == ct.JobStateUp {
			list = append(list, job)
		}
	}
	return list, nil
}

func NewRelease(id string, artifact *ct.Artifact, processes map[string]int) *ct.Release {
	return NewReleaseOmni(id, artifact, processes, false)
}

func NewReleaseOmni(id string, artifact *ct.Artifact, processes map[string]int, omni bool) *ct.Release {
	processTypes := make(map[string]ct.ProcessType, len(processes))
	for t := range processes {
		processTypes[t] = ct.ProcessType{
			Cmd:  []string{"start", t},
			Omni: omni,
		}
	}

	return &ct.Release{
		ID:          id,
		ArtifactIDs: []string{artifact.ID},
		Processes:   processTypes,
	}
}

type FormationStream struct {
	cc *FakeControllerClient
	ch chan<- *ct.ExpandedFormation
}

func (fs *FormationStream) Close() error {
	fs.cc.mtx.Lock()
	defer fs.cc.mtx.Unlock()
	delete(fs.cc.formationStreams, fs.ch)
	close(fs.ch)
	return nil
}

func (fs *FormationStream) Err() error {
	return nil
}
<|endoftext|>


<commit_before>// +build integration

package iaas_test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"testing"

	"github.com/EngineerBetter/concourse-up/iaas"
	"github.com/EngineerBetter/concourse-up/util"
)

func TestGCPProvider_CreateDatabases(t *testing.T) {
	dbName := util.EightRandomLetters()
	setup(dbName, t)
	defer cleanup(dbName)

	_, passwordErr, err := runCommand("gcloud", "sql", "users", "set-password", "postgres", "--instance", dbName, "--password", "password")
	failIfErr(t, err, "Unable to set password with err [%v] and stderr [%v]", passwordErr)

	gcp, err := iaas.New("GCP", "europe-west1")
	failIfErr(t, err, "Unable to create GCP instance: %v")

	err = gcp.CreateDatabases(dbName, "postgres", "password")
	failIfErr(t, err, "Unexpected error setting database password: %v")

	instancesOut, instancesErr, err := runCommand("gcloud", "sql", "databases", "list", "--instance", dbName, "--format", "json")
	failIfErr(t, err, "Unable to list databases due to err: %v, stderr: %v", instancesErr)

	var databases []map[string]interface{}
	json.Unmarshal([]byte(instancesOut), &databases)

	assertDatabaseExists("concourse_atc", databases, t)
	assertDatabaseExists("credhub", databases, t)
	assertDatabaseExists("uaa", databases, t)
}

func failIfErr(t *testing.T, err error, pattern string, args ...interface{}) {
	errAndArgs := append([]interface{}{err}, args...)
	if err != nil {
		t.Fatalf(pattern, errAndArgs...)
	}
}

func runCommand(program string, args ...string) (string, string, error) {
	cmd := exec.Command(program, args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Run()
	outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
	return outStr, errStr, err
}

func assertDatabaseExists(desired string, databases []map[string]interface{}, t *testing.T) {
	for _, database := range databases {
		if database["name"] == desired {
			return
		}
	}
	t.Fatalf("Did not find database %v in %+v", desired, databases)
}

func setup(dbName string, t *testing.T) {
	_, errStr, err := runCommand("gcloud", "sql", "instances", "create", dbName, "--tier=db-g1-small", "--database-version=POSTGRES_9_6", "--region=europe-west1")
	re := `ERROR: \(gcloud\.sql\.instances\.create\).*is taking longer than expected. You can continue waiting for the operation by running`
	r, _ := regexp.Compile(re)
	match := r.MatchString(errStr)
	if err != nil && !match { // and also not a message about timing out
		t.Errorf("Cannot set up database for test error = %v", err)
	}

	if match {
		opStr := `([-a-z0-9]*)[^-a-z0-9]*$`
		opRe, _ := regexp.Compile(opStr)
		op := opRe.FindAllStringSubmatch(errStr, -1)
		opName := op[0][1]
		_, _, err = runCommand("gcloud", "beta", "sql", "operations", "wait", "--project=concourse-up", opName)
		failIfErr(t, err, "Failed with err %v  waiting for the operation %v to finish", op)
	}
}

func cleanup(dbName string) {
	if _, skipTeardown := os.LookupEnv("SKIP_TEARDOWN"); skipTeardown {
		fmt.Println("Skipping teardown")
		return
	}

	runCommand("gcloud", "sql", "instances", "delete", dbName, "--async", "--quiet")
}
<commit_msg>setup and cleanup belong to CreateDatabases integration test<commit_after>// +build integration

package iaas_test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"testing"

	"github.com/EngineerBetter/concourse-up/iaas"
	"github.com/EngineerBetter/concourse-up/util"
)

func TestGCPProvider_CreateDatabases(t *testing.T) {
	dbName := util.EightRandomLetters()
	setupCreateDatabases(dbName, t)
	defer cleanupCreateDatabases(dbName)

	_, passwordErr, err := runCommand("gcloud", "sql", "users", "set-password", "postgres", "--instance", dbName, "--password", "password")
	failIfErr(t, err, "Unable to set password with err [%v] and stderr [%v]", passwordErr)

	gcp, err := iaas.New("GCP", "europe-west1")
	failIfErr(t, err, "Unable to create GCP instance: %v")

	err = gcp.CreateDatabases(dbName, "postgres", "password")
	failIfErr(t, err, "Unexpected error setting database password: %v")

	instancesOut, instancesErr, err := runCommand("gcloud", "sql", "databases", "list", "--instance", dbName, "--format", "json")
	failIfErr(t, err, "Unable to list databases due to err: %v, stderr: %v", instancesErr)

	var databases []map[string]interface{}
	json.Unmarshal([]byte(instancesOut), &databases)

	assertDatabaseExists("concourse_atc", databases, t)
	assertDatabaseExists("credhub", databases, t)
	assertDatabaseExists("uaa", databases, t)
}

func failIfErr(t *testing.T, err error, pattern string, args ...interface{}) {
	errAndArgs := append([]interface{}{err}, args...)
	if err != nil {
		t.Fatalf(pattern, errAndArgs...)
	}
}

func runCommand(program string, args ...string) (string, string, error) {
	cmd := exec.Command(program, args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Run()
	outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
	return outStr, errStr, err
}

func assertDatabaseExists(desired string, databases []map[string]interface{}, t *testing.T) {
	for _, database := range databases {
		if database["name"] == desired {
			return
		}
	}
	t.Fatalf("Did not find database %v in %+v", desired, databases)
}

func setupCreateDatabases(dbName string, t *testing.T) {
	_, errStr, err := runCommand("gcloud", "sql", "instances", "create", dbName, "--tier=db-g1-small", "--database-version=POSTGRES_9_6", "--region=europe-west1")
	re := `ERROR: \(gcloud\.sql\.instances\.create\).*is taking longer than expected. You can continue waiting for the operation by running`
	r, _ := regexp.Compile(re)
	match := r.MatchString(errStr)
	if err != nil && !match { // and also not a message about timing out
		t.Errorf("Cannot set up database for test error = %v", err)
	}

	if match {
		opStr := `([-a-z0-9]*)[^-a-z0-9]*$`
		opRe, _ := regexp.Compile(opStr)
		op := opRe.FindAllStringSubmatch(errStr, -1)
		opName := op[0][1]
		_, _, err = runCommand("gcloud", "beta", "sql", "operations", "wait", "--project=concourse-up", opName)
		failIfErr(t, err, "Failed with err %v  waiting for the operation %v to finish", op)
	}
}

func cleanupCreateDatabases(dbName string) {
	if _, skipTeardown := os.LookupEnv("SKIP_TEARDOWN"); skipTeardown {
		fmt.Println("Skipping teardown")
		return
	}

	runCommand("gcloud", "sql", "instances", "delete", dbName, "--async", "--quiet")
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"fmt"
	"io"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types"
	Cli "github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/promise"
	"github.com/docker/docker/runconfig"
)

// CmdExec runs a command in a running container.
//
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
func (cli *DockerCli) CmdExec(args ...string) error {
	cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)

	execConfig, err := runconfig.ParseExec(cmd, args)
	// just in case the ParseExec does not exit
	if execConfig.Container == "" || err != nil {
		return Cli.StatusError{StatusCode: 1}
	}

	serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, map[string][]string{"Content-Type": "application/json"})
	if err != nil {
		return err
	}

	defer serverResp.body.Close()

	var response types.ContainerExecCreateResponse
	if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil {
		return err
	}

	execID := response.ID

	if execID == "" {
		fmt.Fprintf(cli.out, "exec ID empty")
		return nil
	}

	//Temp struct for execStart so that we don't need to transfer all the execConfig
	execStartCheck := &types.ExecStartCheck{
		Detach: execConfig.Detach,
		Tty:    execConfig.Tty,
	}

	if !execConfig.Detach {
		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
			return err
		}
	} else {
		if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execStartCheck, nil)); err != nil {
			return err
		}
		// For now don't print this - wait for when we support exec wait()
		// fmt.Fprintf(cli.out, "%s\n", execID)
		return nil
	}

	// Interactive exec requested.
	var (
		out, stderr io.Writer
		in          io.ReadCloser
		hijacked    = make(chan io.Closer)
		errCh       chan error
	)

	// Block the return until the chan gets closed
	defer func() {
		logrus.Debugf("End of CmdExec(), Waiting for hijack to finish.")
		if _, ok := <-hijacked; ok {
			fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
		}
	}()

	if execConfig.AttachStdin {
		in = cli.in
	}
	if execConfig.AttachStdout {
		out = cli.out
	}
	if execConfig.AttachStderr {
		if execConfig.Tty {
			stderr = cli.out
		} else {
			stderr = cli.err
		}
	}
	errCh = promise.Go(func() error {
		return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
	})

	// Acknowledge the hijack before starting
	select {
	case closer := <-hijacked:
		// Make sure that hijack gets closed when returning. (result
		// in closing hijack chan and freeing server's goroutines.
		if closer != nil {
			defer closer.Close()
		}
	case err := <-errCh:
		if err != nil {
			logrus.Debugf("Error hijack: %s", err)
			return err
		}
	}

	if execConfig.Tty && cli.isTerminalIn {
		if err := cli.monitorTtySize(execID, true); err != nil {
			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
		}
	}

	if err := <-errCh; err != nil {
		logrus.Debugf("Error hijack: %s", err)
		return err
	}

	var status int
	if _, status, err = getExecExitCode(cli, execID); err != nil {
		return err
	}

	if status != 0 {
		return Cli.StatusError{StatusCode: status}
	}

	return nil
}
<commit_msg>Fix broken type implementation.<commit_after>package client

import (
	"encoding/json"
	"fmt"
	"io"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types"
	Cli "github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/promise"
	"github.com/docker/docker/runconfig"
)

// CmdExec runs a command in a running container.
//
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
func (cli *DockerCli) CmdExec(args ...string) error {
	cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)

	execConfig, err := runconfig.ParseExec(cmd, args)
	// just in case the ParseExec does not exit
	if execConfig.Container == "" || err != nil {
		return Cli.StatusError{StatusCode: 1}
	}

	serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, map[string][]string{"Content-Type": []string{"application/json"}})
	if err != nil {
		return err
	}

	defer serverResp.body.Close()

	var response types.ContainerExecCreateResponse
	if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil {
		return err
	}

	execID := response.ID

	if execID == "" {
		fmt.Fprintf(cli.out, "exec ID empty")
		return nil
	}

	//Temp struct for execStart so that we don't need to transfer all the execConfig
	execStartCheck := &types.ExecStartCheck{
		Detach: execConfig.Detach,
		Tty:    execConfig.Tty,
	}

	if !execConfig.Detach {
		if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
			return err
		}
	} else {
		if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execStartCheck, nil)); err != nil {
			return err
		}
		// For now don't print this - wait for when we support exec wait()
		// fmt.Fprintf(cli.out, "%s\n", execID)
		return nil
	}

	// Interactive exec requested.
	var (
		out, stderr io.Writer
		in          io.ReadCloser
		hijacked    = make(chan io.Closer)
		errCh       chan error
	)

	// Block the return until the chan gets closed
	defer func() {
		logrus.Debugf("End of CmdExec(), Waiting for hijack to finish.")
		if _, ok := <-hijacked; ok {
			fmt.Fprintln(cli.err, "Hijack did not finish (chan still open)")
		}
	}()

	if execConfig.AttachStdin {
		in = cli.in
	}
	if execConfig.AttachStdout {
		out = cli.out
	}
	if execConfig.AttachStderr {
		if execConfig.Tty {
			stderr = cli.out
		} else {
			stderr = cli.err
		}
	}
	errCh = promise.Go(func() error {
		return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
	})

	// Acknowledge the hijack before starting
	select {
	case closer := <-hijacked:
		// Make sure that hijack gets closed when returning. (result
		// in closing hijack chan and freeing server's goroutines.
		if closer != nil {
			defer closer.Close()
		}
	case err := <-errCh:
		if err != nil {
			logrus.Debugf("Error hijack: %s", err)
			return err
		}
	}

	if execConfig.Tty && cli.isTerminalIn {
		if err := cli.monitorTtySize(execID, true); err != nil {
			fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
		}
	}

	if err := <-errCh; err != nil {
		logrus.Debugf("Error hijack: %s", err)
		return err
	}

	var status int
	if _, status, err = getExecExitCode(cli, execID); err != nil {
		return err
	}

	if status != 0 {
		return Cli.StatusError{StatusCode: status}
	}

	return nil
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"

	Cli "github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/ioutils"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/units"
)

// CmdInfo displays system-wide information.
//
// Usage: docker info
func (cli *DockerCli) CmdInfo(args ...string) error {
	cmd := Cli.Subcmd("info", nil, Cli.DockerCommands["info"].Description, true)
	cmd.Require(flag.Exact, 0)

	cmd.ParseFlags(args, true)

	info, err := cli.client.Info()
	if err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
	fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
	ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion)
	ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
	if info.DriverStatus != nil {
		for _, pair := range info.DriverStatus {
			fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
		}
	}
	ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
	ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)

	fmt.Fprintf(cli.out, "Plugins: \n")
	fmt.Fprintf(cli.out, " Volume:")
	for _, driver := range info.Plugins.Volume {
		fmt.Fprintf(cli.out, " %s", driver)
	}
	fmt.Fprintf(cli.out, "\n")
	fmt.Fprintf(cli.out, " Network:")
	for _, driver := range info.Plugins.Network {
		fmt.Fprintf(cli.out, " %s", driver)
	}
	fmt.Fprintf(cli.out, "\n")

	ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
	ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
	ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType)
	ioutils.FprintfIfNotEmpty(cli.out, "Architecture: %s\n", info.Architecture)
	fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
	fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
	ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
	ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)

	if info.Debug {
		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
		fmt.Fprintf(cli.out, " File Descriptors: %d\n", info.NFd)
		fmt.Fprintf(cli.out, " Goroutines: %d\n", info.NGoroutines)
		fmt.Fprintf(cli.out, " System Time: %s\n", info.SystemTime)
		fmt.Fprintf(cli.out, " EventsListeners: %d\n", info.NEventsListener)
		fmt.Fprintf(cli.out, " Init SHA1: %s\n", info.InitSha1)
		fmt.Fprintf(cli.out, " Init Path: %s\n", info.InitPath)
		fmt.Fprintf(cli.out, " Docker Root Dir: %s\n", info.DockerRootDir)
	}

	ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy)
	ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy)
	ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)

	if info.IndexServerAddress != "" {
		u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
		if len(u) > 0 {
			fmt.Fprintf(cli.out, "Username: %v\n", u)
			fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress)
		}
	}

	// Only output these warnings if the server does not support these features
	if info.OSType != "windows" {
		if !info.MemoryLimit {
			fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
		}
		if !info.SwapLimit {
			fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
		}
		if !info.OomKillDisable {
			fmt.Fprintf(cli.err, "WARNING: No oom kill disable support\n")
		}
		if !info.CPUCfsQuota {
			fmt.Fprintf(cli.err, "WARNING: No cpu cfs quota support\n")
		}
		if !info.CPUCfsPeriod {
			fmt.Fprintf(cli.err, "WARNING: No cpu cfs period support\n")
		}
		if !info.CPUShares {
			fmt.Fprintf(cli.err, "WARNING: No cpu shares support\n")
		}
		if !info.CPUSet {
			fmt.Fprintf(cli.err, "WARNING: No cpuset support\n")
		}
		if !info.IPv4Forwarding {
			fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled\n")
		}
		if !info.BridgeNfIptables {
			fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n")
		}
		if !info.BridgeNfIP6tables {
			fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n")
		}
	}

	if info.Labels != nil {
		fmt.Fprintln(cli.out, "Labels:")
		for _, attribute := range info.Labels {
			fmt.Fprintf(cli.out, " %s\n", attribute)
		}
	}

	ioutils.FprintfIfTrue(cli.out, "Experimental: %v\n", info.ExperimentalBuild)
	if info.ClusterStore != "" {
		fmt.Fprintf(cli.out, "Cluster store: %s\n", info.ClusterStore)
	}

	if info.ClusterAdvertise != "" {
		fmt.Fprintf(cli.out, "Cluster advertise: %s\n", info.ClusterAdvertise)
	}
	return nil
}
<commit_msg>api: client: info: print a warning if dm is using a loopback file<commit_after>package client

import (
	"fmt"

	Cli "github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/ioutils"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/units"
)

// CmdInfo displays system-wide information.
//
// Usage: docker info
func (cli *DockerCli) CmdInfo(args ...string) error {
	cmd := Cli.Subcmd("info", nil, Cli.DockerCommands["info"].Description, true)
	cmd.Require(flag.Exact, 0)

	cmd.ParseFlags(args, true)

	info, err := cli.client.Info()
	if err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
	fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
	ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion)
	ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
	if info.DriverStatus != nil {
		for _, pair := range info.DriverStatus {
			fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])

			// print a warning if devicemapper is using a loopback file
			if pair[0] == "Data loop file" {
				fmt.Fprintf(cli.err, " WARNING: Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.")
			}
		}

	}
	ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
	ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)

	fmt.Fprintf(cli.out, "Plugins: \n")
	fmt.Fprintf(cli.out, " Volume:")
	for _, driver := range info.Plugins.Volume {
		fmt.Fprintf(cli.out, " %s", driver)
	}
	fmt.Fprintf(cli.out, "\n")
	fmt.Fprintf(cli.out, " Network:")
	for _, driver := range info.Plugins.Network {
		fmt.Fprintf(cli.out, " %s", driver)
	}
	fmt.Fprintf(cli.out, "\n")

	ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
	ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
	ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType)
	ioutils.FprintfIfNotEmpty(cli.out, "Architecture: %s\n", info.Architecture)
	fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
	fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
	ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
	ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)

	if info.Debug {
		fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
		fmt.Fprintf(cli.out, " File Descriptors: %d\n", info.NFd)
		fmt.Fprintf(cli.out, " Goroutines: %d\n", info.NGoroutines)
		fmt.Fprintf(cli.out, " System Time: %s\n", info.SystemTime)
		fmt.Fprintf(cli.out, " EventsListeners: %d\n", info.NEventsListener)
		fmt.Fprintf(cli.out, " Init SHA1: %s\n", info.InitSha1)
		fmt.Fprintf(cli.out, " Init Path: %s\n", info.InitPath)
		fmt.Fprintf(cli.out, " Docker Root Dir: %s\n", info.DockerRootDir)
	}

	ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy)
	ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy)
	ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)

	if info.IndexServerAddress != "" {
		u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
		if len(u) > 0 {
			fmt.Fprintf(cli.out, "Username: %v\n", u)
			fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress)
		}
	}

	// Only output these warnings if the server does not support these features
	if info.OSType != "windows" {
		if !info.MemoryLimit {
			fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
		}
		if !info.SwapLimit {
			fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
		}
		if !info.OomKillDisable {
			fmt.Fprintf(cli.err, "WARNING: No oom kill disable support\n")
		}
		if !info.CPUCfsQuota {
			fmt.Fprintf(cli.err, "WARNING: No cpu cfs quota support\n")
		}
		if !info.CPUCfsPeriod {
			fmt.Fprintf(cli.err, "WARNING: No cpu cfs period support\n")
		}
		if !info.CPUShares {
			fmt.Fprintf(cli.err, "WARNING: No cpu shares support\n")
		}
		if !info.CPUSet {
			fmt.Fprintf(cli.err, "WARNING: No cpuset support\n")
		}
		if !info.IPv4Forwarding {
			fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled\n")
		}
		if !info.BridgeNfIptables {
			fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n")
		}
		if !info.BridgeNfIP6tables {
			fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n")
		}
	}

	if info.Labels != nil {
		fmt.Fprintln(cli.out, "Labels:")
		for _, attribute := range info.Labels {
			fmt.Fprintf(cli.out, " %s\n", attribute)
		}
	}

	ioutils.FprintfIfTrue(cli.out, "Experimental: %v\n", info.ExperimentalBuild)
	if info.ClusterStore != "" {
		fmt.Fprintf(cli.out, "Cluster store: %s\n", info.ClusterStore)
	}

	if info.ClusterAdvertise != "" {
		fmt.Fprintf(cli.out, "Cluster advertise: %s\n", info.ClusterAdvertise)
	}
	return nil
}
<|endoftext|>


<commit_before>package discoverd

import (
	"fmt"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	hh "github.com/flynn/flynn/pkg/httphelper"
)

// EnvInstanceMeta are environment variables which will be automatically added
// to instance metadata if present.
var EnvInstanceMeta = map[string]struct{}{
	"FLYNN_APP_ID":       {},
	"FLYNN_RELEASE_ID":   {},
	"FLYNN_PROCESS_TYPE": {},
	"FLYNN_JOB_ID":       {},
}

type Heartbeater interface {
	SetMeta(map[string]string) error
	Close() error
	Addr() string
	SetClient(*Client)
}

func (c *Client) maybeAddService(service string) error {
	if err := c.AddService(service, nil); err != nil {
		if !hh.IsObjectExistsError(err) {
			return err
		}
	}
	return nil
}

func (c *Client) AddServiceAndRegister(service, addr string) (Heartbeater, error) {
	if err := c.maybeAddService(service); err != nil {
		return nil, err
	}
	return c.Register(service, addr)
}

func (c *Client) AddServiceAndRegisterInstance(service string, inst *Instance) (Heartbeater, error) {
	if err := c.maybeAddService(service); err != nil {
		return nil, err
	}
	return c.RegisterInstance(service, inst)
}

func (c *Client) Register(service, addr string) (Heartbeater, error) {
	return c.RegisterInstance(service, &Instance{Addr: addr})
}

func (c *Client) RegisterInstance(service string, inst *Instance) (Heartbeater, error) {
	inst.Addr = expandAddr(inst.Addr)
	if inst.Proto == "" {
		inst.Proto = "tcp"
	}
	inst.ID = inst.id()
	// add EnvInstanceMeta if present
	for _, env := range os.Environ() {
		kv := strings.SplitN(env, "=", 2)
		if _, ok := EnvInstanceMeta[kv[0]]; !ok {
			continue
		}
		if inst.Meta == nil {
			inst.Meta = make(map[string]string)
		}
		inst.Meta[kv[0]] = kv[1]
	}
	h := newHeartbeater(c, service, inst)
	firstErr := make(chan error)
	go h.run(firstErr)
	if err := <-firstErr; err != nil {
		return nil, err
	}
	return h, nil
}

func newHeartbeater(c *Client, service string, inst *Instance) *heartbeater {
	h := &heartbeater{
		service: service,
		stop:    make(chan struct{}),
		done:    make(chan struct{}),
		inst:    inst.Clone(),
	}
	h.c.Store(c)
	return h
}

type heartbeater struct {
	c atomic.Value // *Client

	stop chan struct{}
	done chan struct{}

	// Mutex protects inst.Meta
	sync.Mutex
	inst *Instance

	service   string
	closeOnce sync.Once
}

func (h *heartbeater) Close() error {
	h.closeOnce.Do(func() {
		close(h.stop)
		<-h.done
	})
	return nil
}

func (h *heartbeater) SetMeta(meta map[string]string) error {
	h.Lock()
	defer h.Unlock()
	h.inst.Meta = meta
	return h.client().c.Put(fmt.Sprintf("/services/%s/instances/%s", h.service, h.inst.ID), h.inst, nil)
}

func (h *heartbeater) Addr() string {
	return h.inst.Addr
}

func (h *heartbeater) SetClient(c *Client) {
	h.c.Store(c)
}

func (h *heartbeater) client() *Client {
	return h.c.Load().(*Client)
}

const (
	heartbeatInterval        = 5 * time.Second
	heartbeatFailingInterval = 200 * time.Millisecond
)

func (h *heartbeater) run(firstErr chan<- error) {
	path := fmt.Sprintf("/services/%s/instances/%s", h.service, h.inst.ID)
	register := func() error {
		h.Lock()
		defer h.Unlock()
		return h.client().c.Put(path, h.inst, nil)
	}

	err := register()
	firstErr <- err
	if err != nil {
		return
	}
	timer := time.NewTimer(heartbeatInterval)
	for {
		select {
		case <-timer.C:
			if err := register(); err != nil {
				h.client().Logger.Error("heartbeat failed", "service", h.service, "addr", h.inst.Addr, "err", err)
				timer.Reset(heartbeatFailingInterval)
				break
			}
			timer.Reset(heartbeatInterval)
		case <-h.stop:
			h.client().c.Delete(path)
			close(h.done)
			return
		}
	}
}

func expandAddr(addr string) string {
	if addr[0] == ':' {
		return os.Getenv("EXTERNAL_IP") + addr
	}
	return addr
}
<commit_msg>discoverd/client: Add jitter to heartbeats<commit_after>package discoverd

import (
	"fmt"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	hh "github.com/flynn/flynn/pkg/httphelper"
	"github.com/flynn/flynn/pkg/random"
)

// EnvInstanceMeta are environment variables which will be automatically added
// to instance metadata if present.
var EnvInstanceMeta = map[string]struct{}{
	"FLYNN_APP_ID":       {},
	"FLYNN_RELEASE_ID":   {},
	"FLYNN_PROCESS_TYPE": {},
	"FLYNN_JOB_ID":       {},
}

type Heartbeater interface {
	SetMeta(map[string]string) error
	Close() error
	Addr() string
	SetClient(*Client)
}

func (c *Client) maybeAddService(service string) error {
	if err := c.AddService(service, nil); err != nil {
		if !hh.IsObjectExistsError(err) {
			return err
		}
	}
	return nil
}

func (c *Client) AddServiceAndRegister(service, addr string) (Heartbeater, error) {
	if err := c.maybeAddService(service); err != nil {
		return nil, err
	}
	return c.Register(service, addr)
}

func (c *Client) AddServiceAndRegisterInstance(service string, inst *Instance) (Heartbeater, error) {
	if err := c.maybeAddService(service); err != nil {
		return nil, err
	}
	return c.RegisterInstance(service, inst)
}

func (c *Client) Register(service, addr string) (Heartbeater, error) {
	return c.RegisterInstance(service, &Instance{Addr: addr})
}

func (c *Client) RegisterInstance(service string, inst *Instance) (Heartbeater, error) {
	inst.Addr = expandAddr(inst.Addr)
	if inst.Proto == "" {
		inst.Proto = "tcp"
	}
	inst.ID = inst.id()
	// add EnvInstanceMeta if present
	for _, env := range os.Environ() {
		kv := strings.SplitN(env, "=", 2)
		if _, ok := EnvInstanceMeta[kv[0]]; !ok {
			continue
		}
		if inst.Meta == nil {
			inst.Meta = make(map[string]string)
		}
		inst.Meta[kv[0]] = kv[1]
	}
	h := newHeartbeater(c, service, inst)
	firstErr := make(chan error)
	go h.run(firstErr)
	if err := <-firstErr; err != nil {
		return nil, err
	}
	return h, nil
}

func newHeartbeater(c *Client, service string, inst *Instance) *heartbeater {
	h := &heartbeater{
		service: service,
		stop:    make(chan struct{}),
		done:    make(chan struct{}),
		inst:    inst.Clone(),
	}
	h.c.Store(c)
	return h
}

type heartbeater struct {
	c atomic.Value // *Client

	stop chan struct{}
	done chan struct{}

	// Mutex protects inst.Meta
	sync.Mutex
	inst *Instance

	service   string
	closeOnce sync.Once
}

func (h *heartbeater) Close() error {
	h.closeOnce.Do(func() {
		close(h.stop)
		<-h.done
	})
	return nil
}

func (h *heartbeater) SetMeta(meta map[string]string) error {
	h.Lock()
	defer h.Unlock()
	h.inst.Meta = meta
	return h.client().c.Put(fmt.Sprintf("/services/%s/instances/%s", h.service, h.inst.ID), h.inst, nil)
}

func (h *heartbeater) Addr() string {
	return h.inst.Addr
}

func (h *heartbeater) SetClient(c *Client) {
	h.c.Store(c)
}

func (h *heartbeater) client() *Client {
	return h.c.Load().(*Client)
}

const (
	heartbeatInterval        = 5 * time.Second
	heartbeatJitter          = 2 * time.Second
	heartbeatFailingInterval = 200 * time.Millisecond
)

func (h *heartbeater) run(firstErr chan<- error) {
	path := fmt.Sprintf("/services/%s/instances/%s", h.service, h.inst.ID)
	register := func() error {
		h.Lock()
		defer h.Unlock()
		return h.client().c.Put(path, h.inst, nil)
	}

	err := register()
	firstErr <- err
	if err != nil {
		return
	}
	timer := time.NewTimer(nextHeartbeat())
	for {
		select {
		case <-timer.C:
			if err := register(); err != nil {
				h.client().Logger.Error("heartbeat failed", "service", h.service, "addr", h.inst.Addr, "err", err)
				timer.Reset(nextHeartbeatFailing())
				break
			}
			timer.Reset(nextHeartbeat())
		case <-h.stop:
			h.client().c.Delete(path)
			close(h.done)
			return
		}
	}
}

func expandAddr(addr string) string {
	if addr[0] == ':' {
		return os.Getenv("EXTERNAL_IP") + addr
	}
	return addr
}

func nextHeartbeat() time.Duration {
	return heartbeatInterval - time.Duration(random.Math.Int63n(int64(heartbeatJitter)))
}

func nextHeartbeatFailing() time.Duration {
	return heartbeatFailingInterval + time.Duration(random.Math.Int63n(int64(heartbeatFailingInterval)))
}
<|endoftext|>