<commit_before>package service

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

	"math"
	"os"
	"strconv"
	"sync"

	"github.com/syou6162/go-active-learning/lib/example"
	"github.com/syou6162/go-active-learning/lib/fetcher"
	"github.com/syou6162/go-active-learning/lib/model"
	"github.com/syou6162/go-active-learning/lib/util"
)

func (app *goActiveLearningApp) UpdateOrCreateExample(e *model.Example) error {
	return app.repo.UpdateOrCreateExample(e)
}

func (app *goActiveLearningApp) UpdateScore(e *model.Example) error {
	return app.repo.UpdateScore(e)
}

func (app *goActiveLearningApp) InsertExampleFromScanner(scanner *bufio.Scanner) (*model.Example, error) {
	return app.repo.InsertExampleFromScanner(scanner)
}

func (app *goActiveLearningApp) InsertExamplesFromReader(reader io.Reader) error {
	return app.repo.InsertExamplesFromReader(reader)
}

func (app *goActiveLearningApp) SearchExamples() (model.Examples, error) {
	return app.repo.SearchExamples()
}

func (app *goActiveLearningApp) SearchRecentExamples(from time.Time, limit int) (model.Examples, error) {
	return app.repo.SearchRecentExamples(from, limit)
}

func (app *goActiveLearningApp) SearchRecentExamplesByHost(host string, from time.Time, limit int) (model.Examples, error) {
	return app.repo.SearchRecentExamplesByHost(host, from, limit)
}

func (app *goActiveLearningApp) SearchExamplesByLabel(label model.LabelType, limit int) (model.Examples, error) {
	return app.repo.SearchExamplesByLabel(label, limit)
}

func (app *goActiveLearningApp) SearchLabeledExamples(limit int) (model.Examples, error) {
	return app.repo.SearchLabeledExamples(limit)
}

func (app *goActiveLearningApp) SearchPositiveExamples(limit int) (model.Examples, error) {
	return app.repo.SearchPositiveExamples(limit)
}

func (app *goActiveLearningApp) SearchNegativeExamples(limit int) (model.Examples, error) {
	return app.repo.SearchNegativeExamples(limit)
}

func (app *goActiveLearningApp) SearchUnlabeledExamples(limit int) (model.Examples, error) {
	return app.repo.SearchUnlabeledExamples(limit)
}

func (app *goActiveLearningApp) SearchPositiveScoredExamples(limit int) (model.Examples, error) {
	return app.repo.SearchPositiveScoredExamples(limit)
}

func (app *goActiveLearningApp) FindExampleByUlr(url string) (*model.Example, error) {
	return app.repo.FindExampleByUlr(url)
}

func (app *goActiveLearningApp) FindExampleById(id int) (*model.Example, error) {
	return app.repo.FindExampleById(id)
}

func (app *goActiveLearningApp) SearchExamplesByUlrs(urls []string) (model.Examples, error) {
	return app.repo.SearchExamplesByUlrs(urls)
}

func (app *goActiveLearningApp) SearchExamplesByIds(ids []int) (model.Examples, error) {
	return app.repo.SearchExamplesByIds(ids)
}

func (app *goActiveLearningApp) SearchExamplesByKeywords(keywords []string, aggregator string, limit int) (model.Examples, error) {
	return app.repo.SearchExamplesByKeywords(keywords, aggregator, limit)
}

func (app *goActiveLearningApp) DeleteAllExamples() error {
	return app.repo.DeleteAllExamples()
}

func (app *goActiveLearningApp) CountPositiveExamples() (int, error) {
	return app.repo.CountPositiveExamples()
}

func (app *goActiveLearningApp) CountNegativeExamples() (int, error) {
	return app.repo.CountNegativeExamples()
}

func (app *goActiveLearningApp) CountUnlabeledExamples() (int, error) {
	return app.repo.CountUnlabeledExamples()
}

func (app *goActiveLearningApp) UpdateFeatureVector(e *model.Example) error {
	return app.repo.UpdateFeatureVector(e)
}

func (app *goActiveLearningApp) UpdateHatenaBookmark(e *model.Example) error {
	return app.repo.UpdateHatenaBookmark(e)
}

func (app *goActiveLearningApp) UpdateReferringTweets(e *model.Example) error {
	return app.repo.UpdateReferringTweets(e)
}

func hatenaBookmarkByExampleId(hatenaBookmarks []*model.HatenaBookmark) map[int]*model.HatenaBookmark {
	result := make(map[int]*model.HatenaBookmark)
	for _, hb := range hatenaBookmarks {
		result[hb.ExampleId] = hb
	}
	return result
}

func (app *goActiveLearningApp) AttachMetadata(examples model.Examples) error {
	// make sure that example id must be filled
	for _, e := range examples {
		if e.Id == 0 {
			tmp, err := app.FindExampleByUlr(e.Url)
			if err != nil {
				return err
			}
			e.Id = tmp.Id
		}
	}

	fvList, err := app.repo.SearchFeatureVector(examples)
	if err != nil {
		return err
	}

	for _, e := range examples {
		if fv, ok := fvList[e.Id]; ok {
			e.Fv = fv
		}
	}

	return app.AttachLightMetadata(examples)
}

func (app *goActiveLearningApp) AttachLightMetadata(examples model.Examples) error {
	hatenaBookmarks, err := app.repo.SearchHatenaBookmarks(examples)
	if err != nil {
		return err
	}
	hbByid := hatenaBookmarkByExampleId(hatenaBookmarks)
	for _, e := range examples {
		if b, ok := hbByid[e.Id]; ok {
			e.HatenaBookmark = b
		} else {
			e.HatenaBookmark = &model.HatenaBookmark{Bookmarks: []*model.Bookmark{}}
		}
	}

	referringTweetsById, err := app.repo.SearchReferringTweetsList(examples)
	if err != nil {
		return err
	}
	for _, e := range examples {
		if t, ok := referringTweetsById[e.Id]; ok {
			e.ReferringTweets = &t
		} else {
			e.ReferringTweets = &model.ReferringTweets{}
		}
	}
	return nil
}

func (app *goActiveLearningApp) UpdateRecommendation(listName string, examples model.Examples) error {
	listType, err := model.GetRecommendationListType(listName)
	if err != nil {
		return err
	}

	exampleIds := make([]int, 0)
	for _, e := range examples {
		exampleIds = append(exampleIds, e.Id)
	}

	rec := model.Recommendation{RecommendationListType: listType, ExampleIds: exampleIds}
	return app.repo.UpdateRecommendation(rec)
}

func (app *goActiveLearningApp) GetRecommendation(listName string) (model.Examples, error) {
	listType, err := model.GetRecommendationListType(listName)
	if err != nil {
		return nil, err
	}
	rec, err := app.repo.FindRecommendation(listType)
	return app.repo.SearchExamplesByIds(rec.ExampleIds)
}

func (app *goActiveLearningApp) ExistMetadata(e model.Example) bool {
	tmp, err := app.FindExampleByUlr(e.Url)
	if err != nil {
		return false
	}

	if tmp.StatusCode == http.StatusOK {
		return true
	}
	return false
}

func fetchMetaData(e *model.Example) error {
	article, err := fetcher.GetArticle(e.Url)
	if err != nil {
		return err
	}

	e.Title = article.Title
	e.FinalUrl = article.Url
	e.Description = article.Description
	e.OgDescription = article.OgDescription
	e.OgType = article.OgType
	e.OgImage = article.OgImage
	e.Body = article.Body
	e.StatusCode = article.StatusCode
	e.Favicon = article.Favicon

	now := time.Now()
	if article.PublishDate != nil && now.After(*article.PublishDate) {
		e.CreatedAt = *article.PublishDate
		e.UpdatedAt = *article.PublishDate
	}

	fv := util.RemoveDuplicate(example.ExtractFeatures(*e))
	if len(fv) > 100000 {
		return fmt.Errorf("too large features (N = %d) for %s", len(fv), e.FinalUrl)
	}
	e.Fv = fv

	return nil
}

func (app *goActiveLearningApp) Fetch(examples model.Examples) {
	batchSize := 100
	examplesList := make([]model.Examples, 0)
	n := len(examples)

	for i := 0; i < n; i += batchSize {
		max := int(math.Min(float64(i+batchSize), float64(n)))
		examplesList = append(examplesList, examples[i:max])
	}
	for _, l := range examplesList {
		examplesWithMetaData := model.Examples{}
		examplesWithEmptyMetaData := model.Examples{}
		for _, e := range l {
			if !app.ExistMetadata(*e) {
				examplesWithEmptyMetaData = append(examplesWithEmptyMetaData, e)
			} else {
				examplesWithMetaData = append(examplesWithMetaData, e)
			}
		}
		app.AttachMetadata(examplesWithMetaData)

		wg := &sync.WaitGroup{}
		cpus := runtime.NumCPU()
		runtime.GOMAXPROCS(cpus)
		sem := make(chan struct{}, batchSize)
		for idx, e := range examplesWithEmptyMetaData {
			wg.Add(1)
			sem <- struct{}{}
			go func(e *model.Example, idx int) {
				defer wg.Done()
				cnt, err := app.repo.GetErrorCount(e)
				if err != nil {
					log.Println(err.Error())
				}
				if cnt < 5 {
					fmt.Fprintln(os.Stderr, "Fetching("+strconv.Itoa(idx)+"): "+e.Url)
					if err := fetchMetaData(e); err != nil {
						app.repo.IncErrorCount(e)
						log.Println(err.Error())
					}
				}
				<-sem
			}(e, idx)
		}
		wg.Wait()
	}
}
<commit_msg>rename<commit_after>package service

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

	"math"
	"os"
	"strconv"
	"sync"

	"github.com/syou6162/go-active-learning/lib/example"
	"github.com/syou6162/go-active-learning/lib/fetcher"
	"github.com/syou6162/go-active-learning/lib/model"
	"github.com/syou6162/go-active-learning/lib/util"
)

func (app *goActiveLearningApp) UpdateOrCreateExample(e *model.Example) error {
	return app.repo.UpdateOrCreateExample(e)
}

func (app *goActiveLearningApp) UpdateScore(e *model.Example) error {
	return app.repo.UpdateScore(e)
}

func (app *goActiveLearningApp) InsertExampleFromScanner(scanner *bufio.Scanner) (*model.Example, error) {
	return app.repo.InsertExampleFromScanner(scanner)
}

func (app *goActiveLearningApp) InsertExamplesFromReader(reader io.Reader) error {
	return app.repo.InsertExamplesFromReader(reader)
}

func (app *goActiveLearningApp) SearchExamples() (model.Examples, error) {
	return app.repo.SearchExamples()
}

func (app *goActiveLearningApp) SearchRecentExamples(from time.Time, limit int) (model.Examples, error) {
	return app.repo.SearchRecentExamples(from, limit)
}

func (app *goActiveLearningApp) SearchRecentExamplesByHost(host string, from time.Time, limit int) (model.Examples, error) {
	return app.repo.SearchRecentExamplesByHost(host, from, limit)
}

func (app *goActiveLearningApp) SearchExamplesByLabel(label model.LabelType, limit int) (model.Examples, error) {
	return app.repo.SearchExamplesByLabel(label, limit)
}

func (app *goActiveLearningApp) SearchLabeledExamples(limit int) (model.Examples, error) {
	return app.repo.SearchLabeledExamples(limit)
}

func (app *goActiveLearningApp) SearchPositiveExamples(limit int) (model.Examples, error) {
	return app.repo.SearchPositiveExamples(limit)
}

func (app *goActiveLearningApp) SearchNegativeExamples(limit int) (model.Examples, error) {
	return app.repo.SearchNegativeExamples(limit)
}

func (app *goActiveLearningApp) SearchUnlabeledExamples(limit int) (model.Examples, error) {
	return app.repo.SearchUnlabeledExamples(limit)
}

func (app *goActiveLearningApp) SearchPositiveScoredExamples(limit int) (model.Examples, error) {
	return app.repo.SearchPositiveScoredExamples(limit)
}

func (app *goActiveLearningApp) FindExampleByUlr(url string) (*model.Example, error) {
	return app.repo.FindExampleByUlr(url)
}

func (app *goActiveLearningApp) FindExampleById(id int) (*model.Example, error) {
	return app.repo.FindExampleById(id)
}

func (app *goActiveLearningApp) SearchExamplesByUlrs(urls []string) (model.Examples, error) {
	return app.repo.SearchExamplesByUlrs(urls)
}

func (app *goActiveLearningApp) SearchExamplesByIds(ids []int) (model.Examples, error) {
	return app.repo.SearchExamplesByIds(ids)
}

func (app *goActiveLearningApp) SearchExamplesByKeywords(keywords []string, aggregator string, limit int) (model.Examples, error) {
	return app.repo.SearchExamplesByKeywords(keywords, aggregator, limit)
}

func (app *goActiveLearningApp) DeleteAllExamples() error {
	return app.repo.DeleteAllExamples()
}

func (app *goActiveLearningApp) CountPositiveExamples() (int, error) {
	return app.repo.CountPositiveExamples()
}

func (app *goActiveLearningApp) CountNegativeExamples() (int, error) {
	return app.repo.CountNegativeExamples()
}

func (app *goActiveLearningApp) CountUnlabeledExamples() (int, error) {
	return app.repo.CountUnlabeledExamples()
}

func (app *goActiveLearningApp) UpdateFeatureVector(e *model.Example) error {
	return app.repo.UpdateFeatureVector(e)
}

func (app *goActiveLearningApp) UpdateHatenaBookmark(e *model.Example) error {
	return app.repo.UpdateHatenaBookmark(e)
}

func (app *goActiveLearningApp) UpdateReferringTweets(e *model.Example) error {
	return app.repo.UpdateReferringTweets(e)
}

func hatenaBookmarkByExampleId(hatenaBookmarks []*model.HatenaBookmark) map[int]*model.HatenaBookmark {
	result := make(map[int]*model.HatenaBookmark)
	for _, hb := range hatenaBookmarks {
		result[hb.ExampleId] = hb
	}
	return result
}

func (app *goActiveLearningApp) AttachMetadata(examples model.Examples) error {
	// make sure that example id must be filled
	for _, e := range examples {
		if e.Id == 0 {
			tmp, err := app.FindExampleByUlr(e.Url)
			if err != nil {
				return err
			}
			e.Id = tmp.Id
		}
	}

	fvList, err := app.repo.SearchFeatureVector(examples)
	if err != nil {
		return err
	}

	for _, e := range examples {
		if fv, ok := fvList[e.Id]; ok {
			e.Fv = fv
		}
	}

	return app.AttachLightMetadata(examples)
}

func (app *goActiveLearningApp) AttachLightMetadata(examples model.Examples) error {
	hatenaBookmarks, err := app.repo.SearchHatenaBookmarks(examples)
	if err != nil {
		return err
	}
	hbByid := hatenaBookmarkByExampleId(hatenaBookmarks)
	for _, e := range examples {
		if b, ok := hbByid[e.Id]; ok {
			e.HatenaBookmark = b
		} else {
			e.HatenaBookmark = &model.HatenaBookmark{Bookmarks: []*model.Bookmark{}}
		}
	}

	referringTweetsById, err := app.repo.SearchReferringTweetsList(examples)
	if err != nil {
		return err
	}
	for _, e := range examples {
		if tweets, ok := referringTweetsById[e.Id]; ok {
			e.ReferringTweets = &tweets
		} else {
			e.ReferringTweets = &model.ReferringTweets{}
		}
	}
	return nil
}

func (app *goActiveLearningApp) UpdateRecommendation(listName string, examples model.Examples) error {
	listType, err := model.GetRecommendationListType(listName)
	if err != nil {
		return err
	}

	exampleIds := make([]int, 0)
	for _, e := range examples {
		exampleIds = append(exampleIds, e.Id)
	}

	rec := model.Recommendation{RecommendationListType: listType, ExampleIds: exampleIds}
	return app.repo.UpdateRecommendation(rec)
}

func (app *goActiveLearningApp) GetRecommendation(listName string) (model.Examples, error) {
	listType, err := model.GetRecommendationListType(listName)
	if err != nil {
		return nil, err
	}
	rec, err := app.repo.FindRecommendation(listType)
	return app.repo.SearchExamplesByIds(rec.ExampleIds)
}

func (app *goActiveLearningApp) ExistMetadata(e model.Example) bool {
	tmp, err := app.FindExampleByUlr(e.Url)
	if err != nil {
		return false
	}

	if tmp.StatusCode == http.StatusOK {
		return true
	}
	return false
}

func fetchMetaData(e *model.Example) error {
	article, err := fetcher.GetArticle(e.Url)
	if err != nil {
		return err
	}

	e.Title = article.Title
	e.FinalUrl = article.Url
	e.Description = article.Description
	e.OgDescription = article.OgDescription
	e.OgType = article.OgType
	e.OgImage = article.OgImage
	e.Body = article.Body
	e.StatusCode = article.StatusCode
	e.Favicon = article.Favicon

	now := time.Now()
	if article.PublishDate != nil && now.After(*article.PublishDate) {
		e.CreatedAt = *article.PublishDate
		e.UpdatedAt = *article.PublishDate
	}

	fv := util.RemoveDuplicate(example.ExtractFeatures(*e))
	if len(fv) > 100000 {
		return fmt.Errorf("too large features (N = %d) for %s", len(fv), e.FinalUrl)
	}
	e.Fv = fv

	return nil
}

func (app *goActiveLearningApp) Fetch(examples model.Examples) {
	batchSize := 100
	examplesList := make([]model.Examples, 0)
	n := len(examples)

	for i := 0; i < n; i += batchSize {
		max := int(math.Min(float64(i+batchSize), float64(n)))
		examplesList = append(examplesList, examples[i:max])
	}
	for _, l := range examplesList {
		examplesWithMetaData := model.Examples{}
		examplesWithEmptyMetaData := model.Examples{}
		for _, e := range l {
			if !app.ExistMetadata(*e) {
				examplesWithEmptyMetaData = append(examplesWithEmptyMetaData, e)
			} else {
				examplesWithMetaData = append(examplesWithMetaData, e)
			}
		}
		app.AttachMetadata(examplesWithMetaData)

		wg := &sync.WaitGroup{}
		cpus := runtime.NumCPU()
		runtime.GOMAXPROCS(cpus)
		sem := make(chan struct{}, batchSize)
		for idx, e := range examplesWithEmptyMetaData {
			wg.Add(1)
			sem <- struct{}{}
			go func(e *model.Example, idx int) {
				defer wg.Done()
				cnt, err := app.repo.GetErrorCount(e)
				if err != nil {
					log.Println(err.Error())
				}
				if cnt < 5 {
					fmt.Fprintln(os.Stderr, "Fetching("+strconv.Itoa(idx)+"): "+e.Url)
					if err := fetchMetaData(e); err != nil {
						app.repo.IncErrorCount(e)
						log.Println(err.Error())
					}
				}
				<-sem
			}(e, idx)
		}
		wg.Wait()
	}
}
<|endoftext|>


<commit_before>// Package messenger allows you to interact with Facebook chat/Messenger using
// an unofficial API ported from https://github.com/Schmavery/facebook-chat-api.
package messenger

import (
	"errors"
	"net/http"
	"net/url"
)

const (
	facebookURL    = "https://www.facebook.com/"
	facebookOrigin = "https://www.facebook.com"
	loginURL       = "https://www.facebook.com/login.php?login_attempt=1&lwv=110"
	chatURL        = "https://0-edge-chat.facebook.com/pull?"
	threadSyncURL  = "https://www.facebook.com/ajax/mercury/thread_sync.php"
	reconnectURL   = "https://www.facebook.com/ajax/presence/reconnect.php?reason=6"
	readStatusURL  = "https://www.facebook.com/ajax/mercury/change_read_status.php"
	sendMessageURL = "https://www.facebook.com/ajax/mercury/send_messages.php"
	typingURL      = "https://www.facebook.com/ajax/messaging/typ.php"
	syncURL        = "https://www.facebook.com/notifications/sync/?"
	profileURL     = "https://www.facebook.com/chat/user_info/"
	allProfileURL  = "https://www.facebook.com/chat/user_info_all"
	userAgent      = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
	formURLEncoded = "application/x-www-form-urlencoded"
	loggedOutError = 1357001
)

var (
	errNoRedirects = errors.New("no redirects")
	fbURL, _       = url.Parse("https://www.facebook.com")
	edgeURL, _     = url.Parse("https://0-edge-chat.facebook.com")
)

func defaultHeader() http.Header {
	header := make(http.Header)
	header.Set("User-Agent", userAgent)
	header.Set("Origin", facebookOrigin)
	header.Set("Referer", facebookURL)
	return header
}
<commit_msg>Update user agent<commit_after>// Package messenger allows you to interact with Facebook chat/Messenger using
// an unofficial API ported from https://github.com/Schmavery/facebook-chat-api.
package messenger

import (
	"errors"
	"net/http"
	"net/url"
)

const (
	facebookURL    = "https://www.facebook.com/"
	facebookOrigin = "https://www.facebook.com"
	loginURL       = "https://www.facebook.com/login.php?login_attempt=1&lwv=110"
	chatURL        = "https://0-edge-chat.facebook.com/pull?"
	threadSyncURL  = "https://www.facebook.com/ajax/mercury/thread_sync.php"
	reconnectURL   = "https://www.facebook.com/ajax/presence/reconnect.php?reason=6"
	readStatusURL  = "https://www.facebook.com/ajax/mercury/change_read_status.php"
	sendMessageURL = "https://www.facebook.com/ajax/mercury/send_messages.php"
	typingURL      = "https://www.facebook.com/ajax/messaging/typ.php"
	syncURL        = "https://www.facebook.com/notifications/sync/?"
	profileURL     = "https://www.facebook.com/chat/user_info/"
	allProfileURL  = "https://www.facebook.com/chat/user_info_all"
	userAgent      = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
	formURLEncoded = "application/x-www-form-urlencoded"
	loggedOutError = 1357001
)

var (
	errNoRedirects = errors.New("no redirects")
	fbURL, _       = url.Parse("https://www.facebook.com")
	edgeURL, _     = url.Parse("https://0-edge-chat.facebook.com")
)

func defaultHeader() http.Header {
	header := make(http.Header)
	header.Set("User-Agent", userAgent)
	header.Set("Origin", facebookOrigin)
	header.Set("Referer", facebookURL)
	return header
}
<|endoftext|>


<commit_before>package spatial

import (
	"container/list"
	"fmt"
)

// Polygon is a data type for storing simple polygons.
type Polygon []Line

func (p Polygon) String() string {
	s := "Polygon{"
	for _, line := range p {
		s += fmt.Sprintf("%v", line)
	}
	return s + "}"
}

func (p Polygon) ClipToBBox(bbox BBox) []Geom {
	// Is outer ring fully inside?
	orBBox := p[0].BBox()
	if orBBox.SW.X() >= bbox.SW.X() && orBBox.SW.Y() >= bbox.SW.Y() && orBBox.NE.X() <= bbox.NE.X() && orBBox.NE.Y() <= bbox.NE.Y() {
		geom, _ := NewGeom(p)
		return []Geom{geom}
	}

	// This clipping method uses Weiler-Atherton Polygon Clipping
	// It is implemented with in a two-pass manner.
	// Step 1: All edges (subject and clipping) are traversed and intersections are added.
	// Step 2: Starting with an incoming intersection, all edges of the subject polygon are
	//         iterated and until the clipping region is exited, those edges are collected.
	//         After this the clipping polygon is traversed until the original entering
	//         intersection is reached.
	//         This is repeated until the starting intersection is reached.

	// TODO: inner ring handling
	var (
		clipLn = NewLinesFromSegments(BBoxBorders(bbox.SW, bbox.NE))[0]
		subjLn = p[0]
	)
	// weiler-atherton needs clockwise ordering
	if !subjLn.Clockwise() {
		subjLn.Reverse()
	}
	clipLn.Reverse()

	var (
		subjLL = list.New()
		clipLL = list.New()
	)
	// convert subj and clip slices into linked lists
	for _, subjPt := range subjLn {
		subjLL.PushBack(refPoint{pt: subjPt.RoundedCoords()})
		// log.Printf("subjpt: %v", subjPt.RoundedCoords())

	}
	for _, clipPt := range clipLn {
		clipLL.PushBack(clipPt.RoundedCoords())
		// log.Printf("clippt: %v", clipPt.RoundedCoords())
	}

	// build intersections
	nIntsct := insertIntersections(subjLL, clipLL)
	if nIntsct == 0 {
		// Polygons don't intersect at all and polygon is not fully inside.
		return nil
	}

	var (
		lines       []Line
		startIntsct *list.Element
	)
	for subjPt := subjLL.Front(); ; subjPt = nextElemOrWrap(subjLL, subjPt) {
		if subjPt == nil || (startIntsct != nil && subjPt == startIntsct) {
			break
		}
		// entering intersection
		if !subjPt.Value.(refPoint).pt.InPolygon(Polygon{clipLn}) && nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt.InPolygon(Polygon{clipLn}) {
			if startIntsct == nil {
				startIntsct = subjPt
			}

			var (
				nln        Line
				startingPt = nextElemOrWrap(subjLL, subjPt).Value.(refPoint)
			)
			nln = append(nln, startingPt.pt)

			// walk the subject line until there is a leaving intersection
			for subjPt = nextElemOrWrap(subjLL, subjPt); ; subjPt = nextElemOrWrap(subjLL, subjPt) {
				// don't duplicate points
				if len(nln) == 0 || nln[len(nln)-1] != subjPt.Value.(refPoint).pt {
					nln = append(nln, subjPt.Value.(refPoint).pt)
				}

				if len(nln) > 1 && !nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt.InPolygon(Polygon{clipLn}) {
					break
				}
			}
			// walk the clip line until starting intersection is reached
			for clipPt := subjPt.Value.(refPoint).clipRef; ; clipPt = nextElemOrWrap(clipLL, clipPt) {
				if clipPt == nil || clipPt == startingPt.clipRef || startingPt.clipRef == nil {
					break
				}

				// don't duplicate points
				if len(nln) == 0 || nln[len(nln)-1] != clipPt.Value.(Point) {
					nln = append(nln, clipPt.Value.(Point))
				}
			}
			if len(nln) != 0 {
				lines = append(lines, nln)
			}
		}
	}

	var geoms []Geom
	for _, ln := range lines {
		if len(ln) < 3 {
			continue
		}
		ln.Reverse() // invert back to counter-clockwise order
		ng, _ := NewGeom(Polygon{ln})
		geoms = append(geoms, ng)
	}
	return geoms
}

func insertIntersections(subjLL, clipLL *list.List) int {
	var nIntsct = 0
	for subjPt := subjLL.Front(); subjPt != nil; subjPt = subjPt.Next() {
		subjSeg := Segment{subjPt.Value.(refPoint).pt, nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt}
		for clipPt := clipLL.Front(); clipPt != nil; clipPt = clipPt.Next() {
			clipSeg := Segment{clipPt.Value.(Point), nextElemOrWrap(clipLL, clipPt).Value.(Point)}
			if intsct, isIntsct := subjSeg.Intersection(clipSeg); isIntsct {
				nIntsct += 1
				// log.Println(">>>>>>>>", intsct)
				clipRef := clipLL.InsertAfter(intsct, clipPt)
				clipPt = clipPt.Next()

				if existingElem := hasPointElement(subjLL, refPoint{pt: intsct}); existingElem == nil {
					subjLL.InsertAfter(refPoint{
						pt:      intsct,
						clipRef: clipRef,
					}, subjPt)
				} else {
					existingElem.Value = refPoint{
						pt:      intsct,
						clipRef: clipRef,
					}
				}

				if subjPt.Next() != nil {
					subjPt = subjPt.Next()
				}
			}
		}
	}
	return nIntsct
}

func nextElemOrWrap(l *list.List, elem *list.Element) *list.Element {
	if elem.Next() == nil {
		return l.Front()
	}
	return elem.Next()
}

type refPoint struct {
	pt      Point
	clipRef *list.Element
}

func hasPointElement(l *list.List, ref1 refPoint) *list.Element {
	for ref2 := l.Front(); ref2 != nil; ref2 = ref2.Next() {
		if ref2.Value.(refPoint).pt == ref1.pt {
			return ref2
		}
	}
	return nil
}
<commit_msg>lib/spatial: boxed pointlist type<commit_after>package spatial

import (
	"container/list"
	"fmt"
)

type pointList struct {
	l *list.List
}

func newPointList() *pointList {
	return &pointList{
		l: list.New(),
	}
}

func (p *pointList) Front() *list.Element {
	return p.l.Front()
}

func (p *pointList) InsertAfter(v interface{}, mark *list.Element) *list.Element {
	return p.l.InsertAfter(v, mark)
}

func (p *pointList) PushBack(v interface{}) *list.Element {
	return p.l.PushBack(v)
}

func (p *pointList) String() string {
	var buf string
	for elem := p.l.Front(); elem != nil; elem = elem.Next() {
		buf += elem.Value.(refPoint).pt.String() + ", "
	}
	return buf[:len(buf)-1]
}

// Polygon is a data type for storing simple polygons.
type Polygon []Line

func (p Polygon) String() string {
	s := "Polygon{"
	for _, line := range p {
		s += fmt.Sprintf("%v", line)
	}
	return s + "}"
}

func (p Polygon) ClipToBBox(bbox BBox) []Geom {
	// Is outer ring fully inside?
	orBBox := p[0].BBox()
	if orBBox.SW.X() >= bbox.SW.X() && orBBox.SW.Y() >= bbox.SW.Y() && orBBox.NE.X() <= bbox.NE.X() && orBBox.NE.Y() <= bbox.NE.Y() {
		geom, _ := NewGeom(p)
		return []Geom{geom}
	}

	// This clipping method uses Weiler-Atherton Polygon Clipping
	// It is implemented with in a two-pass manner.
	// Step 1: All edges (subject and clipping) are traversed and intersections are added.
	// Step 2: Starting with an incoming intersection, all edges of the subject polygon are
	//         iterated and until the clipping region is exited, those edges are collected.
	//         After this the clipping polygon is traversed until the original entering
	//         intersection is reached.
	//         This is repeated until the starting intersection is reached.

	// TODO: inner ring handling
	var (
		clipLn = NewLinesFromSegments(BBoxBorders(bbox.SW, bbox.NE))[0]
		subjLn = p[0]
	)
	// weiler-atherton needs clockwise ordering
	if !subjLn.Clockwise() {
		subjLn.Reverse()
	}
	clipLn.Reverse()

	var (
		subjLL = list.New()
		clipLL = list.New()
	)
	// convert subj and clip slices into linked lists
	for _, subjPt := range subjLn {
		subjLL.PushBack(refPoint{pt: subjPt.RoundedCoords()})
		// log.Printf("subjpt: %v", subjPt.RoundedCoords())

	}
	for _, clipPt := range clipLn {
		clipLL.PushBack(clipPt.RoundedCoords())
		// log.Printf("clippt: %v", clipPt.RoundedCoords())
	}

	// build intersections
	nIntsct := insertIntersections(subjLL, clipLL)
	if nIntsct == 0 {
		// Polygons don't intersect at all and polygon is not fully inside.
		return nil
	}

	var (
		lines       []Line
		startIntsct *list.Element
	)
	for subjPt := subjLL.Front(); ; subjPt = nextElemOrWrap(subjLL, subjPt) {
		if subjPt == nil || (startIntsct != nil && subjPt == startIntsct) {
			break
		}
		// entering intersection
		if !subjPt.Value.(refPoint).pt.InPolygon(Polygon{clipLn}) && nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt.InPolygon(Polygon{clipLn}) {
			if startIntsct == nil {
				startIntsct = subjPt
			}

			var (
				nln        Line
				startingPt = nextElemOrWrap(subjLL, subjPt).Value.(refPoint)
			)
			nln = append(nln, startingPt.pt)

			// walk the subject line until there is a leaving intersection
			for subjPt = nextElemOrWrap(subjLL, subjPt); ; subjPt = nextElemOrWrap(subjLL, subjPt) {
				// don't duplicate points
				if len(nln) == 0 || nln[len(nln)-1] != subjPt.Value.(refPoint).pt {
					nln = append(nln, subjPt.Value.(refPoint).pt)
				}

				if len(nln) > 1 && !nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt.InPolygon(Polygon{clipLn}) {
					break
				}
			}
			// walk the clip line until starting intersection is reached
			for clipPt := subjPt.Value.(refPoint).clipRef; ; clipPt = nextElemOrWrap(clipLL, clipPt) {
				if clipPt == nil || clipPt == startingPt.clipRef || startingPt.clipRef == nil {
					break
				}

				// don't duplicate points
				if len(nln) == 0 || nln[len(nln)-1] != clipPt.Value.(Point) {
					nln = append(nln, clipPt.Value.(Point))
				}
			}
			if len(nln) != 0 {
				lines = append(lines, nln)
			}
		}
	}

	var geoms []Geom
	for _, ln := range lines {
		if len(ln) < 3 {
			continue
		}
		ln.Reverse() // invert back to counter-clockwise order
		ng, _ := NewGeom(Polygon{ln})
		geoms = append(geoms, ng)
	}
	return geoms
}

func insertIntersections(subjLL, clipLL *list.List) int {
	var nIntsct = 0
	for subjPt := subjLL.Front(); subjPt != nil; subjPt = subjPt.Next() {
		subjSeg := Segment{subjPt.Value.(refPoint).pt, nextElemOrWrap(subjLL, subjPt).Value.(refPoint).pt}
		for clipPt := clipLL.Front(); clipPt != nil; clipPt = clipPt.Next() {
			clipSeg := Segment{clipPt.Value.(Point), nextElemOrWrap(clipLL, clipPt).Value.(Point)}
			if intsct, isIntsct := subjSeg.Intersection(clipSeg); isIntsct {
				nIntsct += 1
				// log.Println(">>>>>>>>", intsct)
				clipRef := clipLL.InsertAfter(intsct, clipPt)
				clipPt = clipPt.Next()

				if existingElem := hasPointElement(subjLL, refPoint{pt: intsct}); existingElem == nil {
					subjLL.InsertAfter(refPoint{
						pt:      intsct,
						clipRef: clipRef,
					}, subjPt)
				} else {
					existingElem.Value = refPoint{
						pt:      intsct,
						clipRef: clipRef,
					}
				}

				if subjPt.Next() != nil {
					subjPt = subjPt.Next()
				}
			}
		}
	}
	return nIntsct
}

func nextElemOrWrap(l *list.List, elem *list.Element) *list.Element {
	if elem.Next() == nil {
		return l.Front()
	}
	return elem.Next()
}

type refPoint struct {
	pt      Point
	clipRef *list.Element
}

func hasPointElement(l *list.List, ref1 refPoint) *list.Element {
	for ref2 := l.Front(); ref2 != nil; ref2 = ref2.Next() {
		if ref2.Value.(refPoint).pt == ref1.pt {
			return ref2
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// Reads all .ronn files & and converts them to string literals
// triggered by "go generate" comment
// Literals are inserted into a map using an init function, this means
// that there are no compilation errors if 'go generate' hasn't been run, just
// blank man files.
func main() {
	fmt.Fprintf(os.Stderr, "Converting man pages into code...\n")
	mandir := "../docs/man"
	fs, err := ioutil.ReadDir(mandir)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open man dir: %v\n", err)
		os.Exit(2)
	}
	out, err := os.Create("../commands/mancontent_gen.go")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create go file: %v\n", err)
		os.Exit(2)
	}
	out.WriteString("package commands\n\nfunc init() {\n")
	out.WriteString("// THIS FILE IS GENERATED, DO NOT EDIT\n")
	out.WriteString("// Use 'go generate ./commands' to update\n")
	fileregex := regexp.MustCompile(`git-lfs(?:-([A-Za-z\-]+))?.\d.ronn`)
	headerregex := regexp.MustCompile(`^###?\s+([A-Za-z0-9 ]+)`)
	// only pick up caps in links to avoid matching optional args
	linkregex := regexp.MustCompile(`\[([A-Z\- ]+)\]`)
	// man links
	manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
	count := 0
	for _, f := range fs {
		if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
			fmt.Fprintf(os.Stderr, "%v\n", f.Name())
			cmd := match[1]
			if len(cmd) == 0 {
				// This is git-lfs.1.ronn
				cmd = "git-lfs"
			}
			out.WriteString("ManPages[\"" + cmd + "\"] = `")
			contentf, err := os.Open(filepath.Join(mandir, f.Name()))
			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
				os.Exit(2)
			}
			// Process the ronn to make it nicer as help text
			scanner := bufio.NewScanner(contentf)
			firstHeaderDone := false
			skipNextLineIfBlank := false
			lastLineWasBullet := false
		scanloop:
			for scanner.Scan() {
				line := scanner.Text()
				trimmedline := strings.TrimSpace(line)
				if skipNextLineIfBlank && len(trimmedline) == 0 {
					skipNextLineIfBlank = false
					lastLineWasBullet = false
					continue
				}

				// Special case headers
				if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
					header := strings.ToLower(hmatch[1])
					switch header {
					case "synopsis":
						// Ignore this, just go direct to command

					case "description":
						// Just skip the header & newline
						skipNextLineIfBlank = true
					case "options":
						out.WriteString("Options:" + "\n")
					case "see also":
						// don't include any content after this
						break scanloop
					default:
						out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
						out.WriteString(strings.Repeat("-", len(header)) + "\n")
					}
					firstHeaderDone = true
					lastLineWasBullet = false
					continue
				}

				if lmatches := linkregex.FindAllStringSubmatch(line, -1); lmatches != nil {
					for _, lmatch := range lmatches {
						linktext := strings.ToLower(lmatch[1])
						line = strings.Replace(line, lmatch[0], `"`+strings.ToUpper(linktext[:1])+linktext[1:]+`"`, 1)
					}
				}
				if manmatches := manlinkregex.FindAllStringSubmatch(line, -1); manmatches != nil {
					for _, manmatch := range manmatches {
						line = strings.Replace(line, manmatch[0], strings.Join(manmatch[1:], " "), 1)
					}
				}

				// Skip content until after first header
				if !firstHeaderDone {
					continue
				}
				// OK, content here

				// remove characters that markdown would render invisible in a text env.
				for _, invis := range []string{"`", "
"} {
					line = strings.Replace(line, invis, "", -1)
				}

				// indent bullets
				if strings.HasPrefix(line, "*") {
					lastLineWasBullet = true
				} else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
					// indent paragraphs under bullets if not already done
					line = "  " + line
				}

				out.WriteString(line + "\n")
			}
			out.WriteString("`\n")
			contentf.Close()
			count++
		}
	}
	out.WriteString("}\n")
	fmt.Fprintf(os.Stderr, "Successfully processed %d man pages.\n", count)

}
<commit_msg>ララララー ラララー ララ<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// Reads all .ronn files & and converts them to string literals
// triggered by "go generate" comment
// Literals are inserted into a map using an init function, this means
// that there are no compilation errors if 'go generate' hasn't been run, just
// blank man files.
func main() {
	buildDir := os.Getenv("GIT_LFS_BUILD_DIR")
	if len(buildDir) == 0 {
		buildDir = ".."
	}
	manDir := filepath.Join(buildDir, "docs/man")

	fmt.Fprintf(os.Stderr, "Converting man pages (%s) into code...\n", manDir)
	fs, err := ioutil.ReadDir(manDir)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open man dir: %v\n", err)
		os.Exit(2)
	}
	out, err := os.Create("../commands/mancontent_gen.go")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create go file: %v\n", err)
		os.Exit(2)
	}
	out.WriteString("package commands\n\nfunc init() {\n")
	out.WriteString("// THIS FILE IS GENERATED, DO NOT EDIT\n")
	out.WriteString("// Use 'go generate ./commands' to update\n")
	fileregex := regexp.MustCompile(`git-lfs(?:-([A-Za-z\-]+))?.\d.ronn`)
	headerregex := regexp.MustCompile(`^###?\s+([A-Za-z0-9 ]+)`)
	// only pick up caps in links to avoid matching optional args
	linkregex := regexp.MustCompile(`\[([A-Z\- ]+)\]`)
	// man links
	manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
	count := 0
	for _, f := range fs {
		if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
			fmt.Fprintf(os.Stderr, "%v\n", f.Name())
			cmd := match[1]
			if len(cmd) == 0 {
				// This is git-lfs.1.ronn
				cmd = "git-lfs"
			}
			out.WriteString("ManPages[\"" + cmd + "\"] = `")
			contentf, err := os.Open(filepath.Join(manDir, f.Name()))
			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
				os.Exit(2)
			}
			// Process the ronn to make it nicer as help text
			scanner := bufio.NewScanner(contentf)
			firstHeaderDone := false
			skipNextLineIfBlank := false
			lastLineWasBullet := false
		scanloop:
			for scanner.Scan() {
				line := scanner.Text()
				trimmedline := strings.TrimSpace(line)
				if skipNextLineIfBlank && len(trimmedline) == 0 {
					skipNextLineIfBlank = false
					lastLineWasBullet = false
					continue
				}

				// Special case headers
				if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
					header := strings.ToLower(hmatch[1])
					switch header {
					case "synopsis":
						// Ignore this, just go direct to command

					case "description":
						// Just skip the header & newline
						skipNextLineIfBlank = true
					case "options":
						out.WriteString("Options:" + "\n")
					case "see also":
						// don't include any content after this
						break scanloop
					default:
						out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
						out.WriteString(strings.Repeat("-", len(header)) + "\n")
					}
					firstHeaderDone = true
					lastLineWasBullet = false
					continue
				}

				if lmatches := linkregex.FindAllStringSubmatch(line, -1); lmatches != nil {
					for _, lmatch := range lmatches {
						linktext := strings.ToLower(lmatch[1])
						line = strings.Replace(line, lmatch[0], `"`+strings.ToUpper(linktext[:1])+linktext[1:]+`"`, 1)
					}
				}
				if manmatches := manlinkregex.FindAllStringSubmatch(line, -1); manmatches != nil {
					for _, manmatch := range manmatches {
						line = strings.Replace(line, manmatch[0], strings.Join(manmatch[1:], " "), 1)
					}
				}

				// Skip content until after first header
				if !firstHeaderDone {
					continue
				}
				// OK, content here

				// remove characters that markdown would render invisible in a text env.
				for _, invis := range []string{"`", "
"} {
					line = strings.Replace(line, invis, "", -1)
				}

				// indent bullets
				if strings.HasPrefix(line, "*") {
					lastLineWasBullet = true
				} else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
					// indent paragraphs under bullets if not already done
					line = "  " + line
				}

				out.WriteString(line + "\n")
			}
			out.WriteString("`\n")
			contentf.Close()
			count++
		}
	}
	out.WriteString("}\n")
	fmt.Fprintf(os.Stderr, "Successfully processed %d man pages.\n", count)

}
<|endoftext|>


<commit_before>package bundlecollection

import (
	"os"
	"path/filepath"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

const (
	fileBundleLogTag = "FileBundle"
	installDirsPerms = os.FileMode(0755)
	enableDirPerms   = os.FileMode(0755)
)

type FileBundle struct {
	installPath string
	enablePath  string
	fs          boshsys.FileSystem
	logger      boshlog.Logger
}

func NewFileBundle(
	installPath, enablePath string,
	fs boshsys.FileSystem,
	logger boshlog.Logger,
) FileBundle {
	return FileBundle{
		installPath: installPath,
		enablePath:  enablePath,
		fs:          fs,
		logger:      logger,
	}
}

func (b FileBundle) Install(sourcePath string) (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Installing %v", b)

	err := b.fs.Chmod(sourcePath, installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Settting permissions on source directory")
	}

	err = b.fs.MkdirAll(filepath.Dir(b.installPath), installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Creating parent installation directory")
	}

	// Rename MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	err = b.fs.Rename(sourcePath, b.installPath)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Moving to installation directory")
	}

	return b.fs, b.installPath, nil
}

func (b FileBundle) InstallWithoutContents() (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Installing without contents %v", b)

	// MkdirAll MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	err := b.fs.MkdirAll(b.installPath, installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Creating installation directory")
	}

	return b.fs, b.installPath, nil
}

func (b FileBundle) GetInstallPath() (boshsys.FileSystem, string, error) {
	path := b.installPath
	if !b.fs.FileExists(path) {
		return nil, "", bosherr.Error("install dir does not exist")
	}

	return b.fs, path, nil
}

func (b FileBundle) IsInstalled() (bool, error) {
	return b.fs.FileExists(b.installPath), nil
}

func (b FileBundle) Enable() (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Enabling %v", b)

	if !b.fs.FileExists(b.installPath) {
		return nil, "", bosherr.Error("bundle must be installed")
	}

	err := b.fs.MkdirAll(filepath.Dir(b.enablePath), enableDirPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "failed to create enable dir")
	}

	err = b.fs.Symlink(b.installPath, b.enablePath)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "failed to enable")
	}

	return b.fs, b.enablePath, nil
}

func (b FileBundle) Disable() error {
	b.logger.Debug(fileBundleLogTag, "Disabling %v", b)

	target, err := b.fs.ReadLink(b.enablePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return bosherr.WrapError(err, "Reading symlink")
	}

	if target == b.installPath {
		return b.fs.RemoveAll(b.enablePath)
	}

	return nil
}

func (b FileBundle) Uninstall() error {
	b.logger.Debug(fileBundleLogTag, "Uninstalling %v", b)

	// RemoveAll MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	return b.fs.RemoveAll(b.installPath)
}
<commit_msg>Spelling fix in error message.<commit_after>package bundlecollection

import (
	"os"
	"path/filepath"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

const (
	fileBundleLogTag = "FileBundle"
	installDirsPerms = os.FileMode(0755)
	enableDirPerms   = os.FileMode(0755)
)

type FileBundle struct {
	installPath string
	enablePath  string
	fs          boshsys.FileSystem
	logger      boshlog.Logger
}

func NewFileBundle(
	installPath, enablePath string,
	fs boshsys.FileSystem,
	logger boshlog.Logger,
) FileBundle {
	return FileBundle{
		installPath: installPath,
		enablePath:  enablePath,
		fs:          fs,
		logger:      logger,
	}
}

func (b FileBundle) Install(sourcePath string) (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Installing %v", b)

	err := b.fs.Chmod(sourcePath, installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Setting permissions on source directory")
	}

	err = b.fs.MkdirAll(filepath.Dir(b.installPath), installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Creating parent installation directory")
	}

	// Rename MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	err = b.fs.Rename(sourcePath, b.installPath)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Moving to installation directory")
	}

	return b.fs, b.installPath, nil
}

func (b FileBundle) InstallWithoutContents() (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Installing without contents %v", b)

	// MkdirAll MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	err := b.fs.MkdirAll(b.installPath, installDirsPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "Creating installation directory")
	}

	return b.fs, b.installPath, nil
}

func (b FileBundle) GetInstallPath() (boshsys.FileSystem, string, error) {
	path := b.installPath
	if !b.fs.FileExists(path) {
		return nil, "", bosherr.Error("install dir does not exist")
	}

	return b.fs, path, nil
}

func (b FileBundle) IsInstalled() (bool, error) {
	return b.fs.FileExists(b.installPath), nil
}

func (b FileBundle) Enable() (boshsys.FileSystem, string, error) {
	b.logger.Debug(fileBundleLogTag, "Enabling %v", b)

	if !b.fs.FileExists(b.installPath) {
		return nil, "", bosherr.Error("bundle must be installed")
	}

	err := b.fs.MkdirAll(filepath.Dir(b.enablePath), enableDirPerms)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "failed to create enable dir")
	}

	err = b.fs.Symlink(b.installPath, b.enablePath)
	if err != nil {
		return nil, "", bosherr.WrapError(err, "failed to enable")
	}

	return b.fs, b.enablePath, nil
}

func (b FileBundle) Disable() error {
	b.logger.Debug(fileBundleLogTag, "Disabling %v", b)

	target, err := b.fs.ReadLink(b.enablePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return bosherr.WrapError(err, "Reading symlink")
	}

	if target == b.installPath {
		return b.fs.RemoveAll(b.enablePath)
	}

	return nil
}

func (b FileBundle) Uninstall() error {
	b.logger.Debug(fileBundleLogTag, "Uninstalling %v", b)

	// RemoveAll MUST be the last possibly-failing operation
	// because IsInstalled() relies on installPath presence.
	return b.fs.RemoveAll(b.installPath)
}
<|endoftext|>


<commit_before>package cruncy

// VERSION of the application
const VERSION = "0.7.2"
<commit_msg>0.7.3<commit_after>package cruncy

// VERSION of the application
const VERSION = "0.7.3"
<|endoftext|>


<commit_before>package yiigo

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
)

// AESCBCEncrypt AES CBC encrypt with PKCS#7 padding
func AESCBCEncrypt(plainText, key []byte, iv ...byte) ([]byte, error) {
	block, err := aes.NewCipher(key)

	if err != nil {
		return nil, err
	}

	plainText = PKCS7Padding(plainText, len(key))

	cipherText := make([]byte, len(plainText))

	if len(iv) == 0 {
		iv = key[:block.BlockSize()]
	}

	blockMode := cipher.NewCBCEncrypter(block, iv)
	blockMode.CryptBlocks(cipherText, plainText)

	return cipherText, nil
}

// AESCBCDecrypt AES CBC decrypt with PKCS#7 unpadding
func AESCBCDecrypt(cipherText, key []byte, iv ...byte) ([]byte, error) {
	block, err := aes.NewCipher(key)

	if err != nil {
		return nil, err
	}

	plainText := make([]byte, len(cipherText))

	if len(iv) == 0 {
		iv = key[:block.BlockSize()]
	}

	blockMode := cipher.NewCBCDecrypter(block, iv)
	blockMode.CryptBlocks(plainText, cipherText)

	return PKCS7UnPadding(plainText, len(key)), nil
}

// PKCS7Padding PKCS7 padding
func PKCS7Padding(cipherText []byte, blockSize int) []byte {
	padding := blockSize - len(cipherText)%blockSize

	if padding == 0 {
		padding = blockSize
	}

	padText := bytes.Repeat([]byte{byte(padding)}, padding)

	return append(cipherText, padText...)
}

// PKCS7UnPadding PKCS7 unpadding
func PKCS7UnPadding(plainText []byte, blockSize int) []byte {
	l := len(plainText)
	unpadding := int(plainText[l-1])

	if unpadding < 1 || unpadding > blockSize {
		unpadding = 0
	}

	return plainText[:(l - unpadding)]
}
<commit_msg>PKCS#7<commit_after>package yiigo

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
)

// AESCBCEncrypt AES CBC encrypt with PKCS#7 padding
func AESCBCEncrypt(plainText, key []byte, iv ...byte) ([]byte, error) {
	block, err := aes.NewCipher(key)

	if err != nil {
		return nil, err
	}

	plainText = PKCS7Padding(plainText, len(key))

	cipherText := make([]byte, len(plainText))

	if len(iv) == 0 {
		iv = key[:block.BlockSize()]
	}

	blockMode := cipher.NewCBCEncrypter(block, iv)
	blockMode.CryptBlocks(cipherText, plainText)

	return cipherText, nil
}

// AESCBCDecrypt AES CBC decrypt with PKCS#7 unpadding
func AESCBCDecrypt(cipherText, key []byte, iv ...byte) ([]byte, error) {
	block, err := aes.NewCipher(key)

	if err != nil {
		return nil, err
	}

	plainText := make([]byte, len(cipherText))

	if len(iv) == 0 {
		iv = key[:block.BlockSize()]
	}

	blockMode := cipher.NewCBCDecrypter(block, iv)
	blockMode.CryptBlocks(plainText, cipherText)

	return PKCS7UnPadding(plainText, len(key)), nil
}

// PKCS7Padding PKCS7 padding
func PKCS7Padding(cipherText []byte, blockSize int) []byte {
	padding := blockSize - len(cipherText)%blockSize

	if padding == 0 {
		padding = blockSize
	}

	padText := bytes.Repeat([]byte{byte(padding)}, padding)

	return append(cipherText, padText...)
}

// PKCS7UnPadding PKCS7 unpadding
func PKCS7UnPadding(plainText []byte, blockSize int) []byte {
	l := len(plainText)
	unpadding := int(plainText[l-1])

	if unpadding < 0 || unpadding > blockSize {
		unpadding = 0
	}

	return plainText[:(l - unpadding)]
}
<|endoftext|>


<commit_before>package storage

import (
	"time"

	"github.com/pkg/errors"

	"github.com/yuuki/diamondb/lib/series"
	"github.com/yuuki/diamondb/lib/storage/dynamo"
	"github.com/yuuki/diamondb/lib/storage/redis"
)

// Fetcher defines the interface for data store reader.
type Fetcher interface {
	Fetch(string, time.Time, time.Time) (series.SeriesSlice, error)
}

// Store provides each data store client.
type Store struct {
	Redis    *redis.Redis
	DynamoDB *dynamo.DynamoDB
	// s3 client
}

// NewStore create a new Store wrapped by Fetcher.
func NewStore() Fetcher {
	return &Store{
		Redis:    redis.NewRedis(),
		DynamoDB: dynamo.NewDynamoDB(),
	}
}

// FetchSeriesSlice fetches series from Redis, DynamoDB and S3.
func (s *Store) Fetch(name string, start, end time.Time) (series.SeriesSlice, error) {
	sm1, err := s.Redis.Fetch(name, start, end)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Failed to redis.FetchMetrics %s %d %d",
			name, start.Unix(), end.Unix(),
		)
	}
	sm2, err := s.DynamoDB.Fetch(name, start, end)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Failed to FetchMetricsFromDynamoDB %s %d %d",
			name, start.Unix(), end.Unix(),
		)
	}
	sm := sm1.MergePointsToSlice(sm2)
	// TODO S3
	return sm, nil
}
<commit_msg>Fix comment<commit_after>package storage

import (
	"time"

	"github.com/pkg/errors"

	"github.com/yuuki/diamondb/lib/series"
	"github.com/yuuki/diamondb/lib/storage/dynamo"
	"github.com/yuuki/diamondb/lib/storage/redis"
)

// Fetcher defines the interface for data store reader.
type Fetcher interface {
	Fetch(string, time.Time, time.Time) (series.SeriesSlice, error)
}

// Store provides each data store client.
type Store struct {
	Redis    *redis.Redis
	DynamoDB *dynamo.DynamoDB
	// s3 client
}

// NewStore create a new Store wrapped by Fetcher.
func NewStore() Fetcher {
	return &Store{
		Redis:    redis.NewRedis(),
		DynamoDB: dynamo.NewDynamoDB(),
	}
}

// Fetch fetches series from Redis, DynamoDB and S3.
func (s *Store) Fetch(name string, start, end time.Time) (series.SeriesSlice, error) {
	sm1, err := s.Redis.Fetch(name, start, end)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Failed to redis.FetchMetrics %s %d %d",
			name, start.Unix(), end.Unix(),
		)
	}
	sm2, err := s.DynamoDB.Fetch(name, start, end)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Failed to FetchMetricsFromDynamoDB %s %d %d",
			name, start.Unix(), end.Unix(),
		)
	}
	sm := sm1.MergePointsToSlice(sm2)
	// TODO S3
	return sm, nil
}
<|endoftext|>


<commit_before>package disruptor

import "sync/atomic"

type Cursor [cpuCacheLinePadding]int64

func NewCursor() *Cursor {
	this := &Cursor{}
	this.Store(InitialCursorSequenceValue)
	return this
}

func (this *Cursor) Store(sequence int64) { atomic.StoreInt64(&this[0], sequence) }
func (this *Cursor) Load() int64          { return atomic.LoadInt64(&this[0]) }

const cpuCacheLinePadding = 8
<commit_msg>Inlined constant; revised constructor.<commit_after>package disruptor

import "sync/atomic"

type Cursor [8]int64 // prevent false sharing of the cursor by padding the CPU cache line with 64 *bytes* of data.

func NewCursor() *Cursor {
	var this Cursor
	this[0] = InitialCursorSequenceValue
	return &this
}

func (this *Cursor) Store(sequence int64) { atomic.StoreInt64(&this[0], sequence) }
func (this *Cursor) Load() int64          { return atomic.LoadInt64(&this[0]) }
<|endoftext|>


<commit_before>/*
CompileDaemon is a very simple compile daemon for Go.

CompileDaemon watches your .go files in a directory and invokes `go build`
if a file changes.

Examples

In its simplest form, the defaults will do. With the current working directory set
to the source directory you can simply…

    $ CompileDaemon

… and it will recompile your code whenever you save a source file.

If you want it to also run your program each time it builds you might add…

    $ CompileDaemon -command="./MyProgram -my-options"

… and it will also keep a copy of your program running. Killing the old one and
starting a new one each time you build. For advanced usage you can also supply
the changed file to the command by doing…

	$ CompileDaemon -command="./MyProgram -my-options %[1]s"

…but note that this will not be set on the first start.

You may find that you need to exclude some directories and files from
monitoring, such as a .git repository or emacs temporary files…

    $ CompileDaemon -exclude-dir=.git -exclude=".#*"

If you want to monitor files other than .go and .c files you might…

    $ CompileDaemon -include=Makefile -include="*.less" -include="*.tmpl"

Options

There are command line options.

	FILE SELECTION
	-directory=XXX    – which directory to monitor for changes
	-recursive=XXX    – look into subdirectories
	-exclude-dir=XXX  – exclude directories matching glob pattern XXX
	-exlude=XXX       – exclude files whose basename matches glob pattern XXX
	-include=XXX      – include files whose basename matches glob pattern XXX
	-pattern=XXX      – include files whose path matches regexp XXX

	MISC
	-color            - enable colorized output
	-log-prefix       - Enable/disable stdout/stderr labelling for the child process
	-graceful-kill    - On supported platforms, send the child process a SIGTERM to
	                    allow it to exit gracefully if possible.
	ACTIONS
	-build=CCC        – Execute CCC to rebuild when a file changes
	-command=CCC      – Run command CCC after a successful build, stops previous command first

*/
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/fatih/color"
	"gopkg.in/fsnotify.v1"
)

// Milliseconds to wait for the next job to begin after a file change
const WorkDelay = 900

// Default pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

type globList []string

func (g *globList) String() string {
	return fmt.Sprint(*g)
}
func (g *globList) Set(value string) error {
	*g = append(*g, value)
	return nil
}
func (g *globList) Matches(value string) bool {
	for _, v := range *g {
		if match, err := filepath.Match(v, value); err != nil {
			log.Fatalf("Bad pattern \"%s\": %s", v, err.Error())
		} else if match {
			return true
		}
	}
	return false
}

var (
	flag_directory    = flag.String("directory", ".", "Directory to watch for changes")
	flag_pattern      = flag.String("pattern", FilePattern, "Pattern of watched files")
	flag_command      = flag.String("command", "", "Command to run and restart after build")
	flag_command_stop = flag.Bool("command-stop", false, "Stop command before building")
	flag_recursive    = flag.Bool("recursive", true, "Watch all dirs. recursively")
	flag_build        = flag.String("build", "go build", "Command to rebuild after changes")
	flag_build_dir    = flag.String("build-dir", "", "Directory to run build command in.  Defaults to directory")
	flag_color        = flag.Bool("color", false, "Colorize output for CompileDaemon status messages")
	flag_logprefix    = flag.Bool("log-prefix", true, "Print log timestamps and subprocess stderr/stdout output")
	flag_gracefulkill = flag.Bool("graceful-kill", false, "Gracefully attempt to kill the child process by sending a SIGTERM first")

	// initialized in main() due to custom type.
	flag_excludedDirs  globList
	flag_excludedFiles globList
	flag_includedFiles globList
)

func okColor(format string, args ...interface{}) string {
	if *flag_color {
		return color.GreenString(format, args...)
	} else {
		return fmt.Sprintf(format, args...)
	}
}

func failColor(format string, args ...interface{}) string {
	if *flag_color {
		return color.RedString(format, args...)
	} else {
		return fmt.Sprintf(format, args...)
	}
}

// Run `go build` and print the output if something's gone wrong.
func build() bool {
	log.Println(okColor("Running build command!"))

	args := strings.Split(*flag_build, " ")
	if len(args) == 0 {
		// If the user has specified and empty then we are done.
		return true
	}

	cmd := exec.Command(args[0], args[1:]...)

	if *flag_build_dir != "" {
		cmd.Dir = *flag_build_dir
	} else {
		cmd.Dir = *flag_directory
	}

	output, err := cmd.CombinedOutput()

	if err == nil {
		log.Println(okColor("Build ok."))
	} else {
		log.Println(failColor("Error while building:\n"), failColor(string(output)))
	}

	return err == nil
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Accept build jobs and start building when there are no jobs rushing in.
// The inrush protection is WorkDelay milliseconds long, in this period
// every incoming job will reset the timer.
func builder(jobs <-chan string, buildStarted chan<- string, buildDone chan<- bool) {
	createThreshold := func() <-chan time.Time {
		return time.After(time.Duration(WorkDelay * time.Millisecond))
	}

	threshold := createThreshold()
	eventPath := ""

	for {
		select {
		case eventPath = <-jobs:
			threshold = createThreshold()
		case <-threshold:
			buildStarted <- eventPath
			buildDone <- build()
		}
	}
}

func logger(pipeChan <-chan io.ReadCloser) {
	dumper := func(pipe io.ReadCloser, prefix string) {
		reader := bufio.NewReader(pipe)

	readloop:
		for {
			line, err := reader.ReadString('\n')

			if err != nil {
				break readloop
			}

			if *flag_logprefix {
				log.Print(prefix, " ", line)
			} else {
				log.Print(line)
			}
		}
	}

	for {
		pipe := <-pipeChan
		go dumper(pipe, "stdout:")

		pipe = <-pipeChan
		go dumper(pipe, "stderr:")
	}
}

// Start the supplied command and return stdout and stderr pipes for logging.
func startCommand(command string) (cmd *exec.Cmd, stdout io.ReadCloser, stderr io.ReadCloser, err error) {
	args := strings.Split(command, " ")
	cmd = exec.Command(args[0], args[1:]...)

	if stdout, err = cmd.StdoutPipe(); err != nil {
		err = fmt.Errorf("can't get stdout pipe for command: %s", err)
		return
	}

	if stderr, err = cmd.StderrPipe(); err != nil {
		err = fmt.Errorf("can't get stderr pipe for command: %s", err)
		return
	}

	if err = cmd.Start(); err != nil {
		err = fmt.Errorf("can't start command: %s", err)
		return
	}

	return
}

// Run the command in the given string and restart it after
// a message was received on the buildDone channel.
func runner(commandTemplate string, buildStarted <-chan string, buildSuccess <-chan bool) {
	var currentProcess *os.Process
	pipeChan := make(chan io.ReadCloser)

	go logger(pipeChan)

	go func() {
		sigChan := make(chan os.Signal, 1)
		signal.Notify(sigChan, fatalSignals...)
		<-sigChan
		log.Println(okColor("Received signal, terminating cleanly."))
		if currentProcess != nil {
			killProcess(currentProcess)
		}
		os.Exit(0)
	}()

	for {
		eventPath := <-buildStarted

		// append %0.s to use format specifier even if not supplied by user
		// to suppress warning in returned string.
		command := fmt.Sprintf("%0.s" + commandTemplate, eventPath)

		if !*flag_command_stop {
			if !<-buildSuccess {
				continue
			}
		}

		if currentProcess != nil {
			killProcess(currentProcess)
		}
		if *flag_command_stop {
			log.Println(okColor("Command stopped. Waiting for build to complete."))
			<-buildSuccess
		}

		log.Println(okColor("Restarting the given command."))
		cmd, stdoutPipe, stderrPipe, err := startCommand(command)

		if err != nil {
			log.Fatal(failColor("Could not start command: %s", err))
		}

		pipeChan <- stdoutPipe
		pipeChan <- stderrPipe

		currentProcess = cmd.Process
	}
}

func killProcess(process *os.Process) {
	if *flag_gracefulkill {
		killProcessGracefully(process)
	} else {
		killProcessHard(process)
	}
}

func killProcessHard(process *os.Process) {
	log.Println(okColor("Hard stopping the current process.."))

	if err := process.Kill(); err != nil {
		log.Fatal(failColor("Could not kill child process. Aborting due to danger of infinite forks."))
	}

	if _, err := process.Wait(); err != nil {
		log.Fatal(failColor("Could not wait for child process. Aborting due to danger of infinite forks."))
	}
}

func killProcessGracefully(process *os.Process) {
	done := make(chan error, 1)
	go func() {
		log.Println(okColor("Gracefully stopping the current process.."))
		if err := terminateGracefully(process); err != nil {
			done <- err
			return
		}
		_, err := process.Wait()
		done <- err
	}()

	select {
	case <-time.After(3 * time.Second):
		log.Println(failColor("Could not gracefully stop the current process, proceeding to hard stop."))
		killProcessHard(process)
		<-done
	case err := <-done:
		if err != nil {
			log.Fatal(failColor("Could not kill child process. Aborting due to danger of infinite forks."))
		}
	}
}

func flusher(buildStarted <-chan string, buildSuccess <-chan bool) {
	for {
		<-buildStarted
		<-buildSuccess
	}
}

func main() {
	flag.Var(&flag_excludedDirs, "exclude-dir", " Don't watch directories matching this name")
	flag.Var(&flag_excludedFiles, "exclude", " Don't watch files matching this name")
	flag.Var(&flag_includedFiles, "include", " Watch files matching this name")

	flag.Parse()

	if !*flag_logprefix {
		log.SetFlags(0)
	}

	if *flag_directory == "" {
		fmt.Fprintf(os.Stderr, "-directory=... is required.\n")
		os.Exit(1)
	}

	if *flag_gracefulkill && !gracefulTerminationPossible() {
		log.Fatal("Graceful termination is not supported on your platform.")
	}

	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if *flag_recursive == true {
		err = filepath.Walk(*flag_directory, func(path string, info os.FileInfo, err error) error {
			if err == nil && info.IsDir() {
				if flag_excludedDirs.Matches(info.Name()) {
					return filepath.SkipDir
				} else {
					return watcher.Add(path)
				}
			}
			return err
		})

		if err != nil {
			log.Fatal("filepath.Walk():", err)
		}

		if err := watcher.Add(*flag_directory); err != nil {
			log.Fatal("watcher.Add():", err)
		}

	} else {
		if err := watcher.Add(*flag_directory); err != nil {
			log.Fatal("watcher.Add():", err)
		}
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)
	buildSuccess := make(chan bool)
	buildStarted := make(chan string)

	go builder(jobs, buildStarted, buildSuccess)

	if *flag_command != "" {
		go runner(*flag_command, buildStarted, buildSuccess)
	} else {
		go flusher(buildStarted, buildSuccess)
	}

	for {
		select {
		case ev := <-watcher.Events:
			if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Write == fsnotify.Write || ev.Op&fsnotify.Create == fsnotify.Create {
				base := filepath.Base(ev.Name)

				// Assume it is a directory and track it.
				if *flag_recursive == true && !flag_excludedDirs.Matches(ev.Name) {
					watcher.Add(ev.Name)
				}

				if flag_includedFiles.Matches(base) || matchesPattern(pattern, ev.Name) {
					if !flag_excludedFiles.Matches(base) {
						jobs <- ev.Name
					}
				}
			}

		case err := <-watcher.Errors:
			if v, ok := err.(*os.SyscallError); ok {
				if v.Err == syscall.EINTR {
					continue
				}
				log.Fatal("watcher.Error: SyscallError:", v)
			}
			log.Fatal("watcher.Error:", err)
		}
	}
}
<commit_msg>Unify capitalization in documentation<commit_after>/*
CompileDaemon is a very simple compile daemon for Go.

CompileDaemon watches your .go files in a directory and invokes `go build`
if a file changes.

Examples

In its simplest form, the defaults will do. With the current working directory set
to the source directory you can simply…

    $ CompileDaemon

… and it will recompile your code whenever you save a source file.

If you want it to also run your program each time it builds you might add…

    $ CompileDaemon -command="./MyProgram -my-options"

… and it will also keep a copy of your program running. Killing the old one and
starting a new one each time you build. For advanced usage you can also supply
the changed file to the command by doing…

	$ CompileDaemon -command="./MyProgram -my-options %[1]s"

…but note that this will not be set on the first start.

You may find that you need to exclude some directories and files from
monitoring, such as a .git repository or emacs temporary files…

    $ CompileDaemon -exclude-dir=.git -exclude=".#*"

If you want to monitor files other than .go and .c files you might…

    $ CompileDaemon -include=Makefile -include="*.less" -include="*.tmpl"

Options

There are command line options.

	FILE SELECTION
	-directory=XXX    – Which directory to monitor for changes
	-recursive=XXX    – Look into subdirectories
	-exclude-dir=XXX  – Exclude directories matching glob pattern XXX
	-exlude=XXX       – Exclude files whose basename matches glob pattern XXX
	-include=XXX      – Include files whose basename matches glob pattern XXX
	-pattern=XXX      – Include files whose path matches regexp XXX

	MISC
	-color            - Enable colorized output
	-log-prefix       - Enable/disable stdout/stderr labelling for the child process
	-graceful-kill    - On supported platforms, send the child process a SIGTERM to
	                    allow it to exit gracefully if possible.
	ACTIONS
	-build=CCC        – Execute CCC to rebuild when a file changes
	-command=CCC      – Run command CCC after a successful build, stops previous command first

*/
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/fatih/color"
	"gopkg.in/fsnotify.v1"
)

// Milliseconds to wait for the next job to begin after a file change
const WorkDelay = 900

// Default pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

type globList []string

func (g *globList) String() string {
	return fmt.Sprint(*g)
}
func (g *globList) Set(value string) error {
	*g = append(*g, value)
	return nil
}
func (g *globList) Matches(value string) bool {
	for _, v := range *g {
		if match, err := filepath.Match(v, value); err != nil {
			log.Fatalf("Bad pattern \"%s\": %s", v, err.Error())
		} else if match {
			return true
		}
	}
	return false
}

var (
	flag_directory    = flag.String("directory", ".", "Directory to watch for changes")
	flag_pattern      = flag.String("pattern", FilePattern, "Pattern of watched files")
	flag_command      = flag.String("command", "", "Command to run and restart after build")
	flag_command_stop = flag.Bool("command-stop", false, "Stop command before building")
	flag_recursive    = flag.Bool("recursive", true, "Watch all dirs. recursively")
	flag_build        = flag.String("build", "go build", "Command to rebuild after changes")
	flag_build_dir    = flag.String("build-dir", "", "Directory to run build command in.  Defaults to directory")
	flag_color        = flag.Bool("color", false, "Colorize output for CompileDaemon status messages")
	flag_logprefix    = flag.Bool("log-prefix", true, "Print log timestamps and subprocess stderr/stdout output")
	flag_gracefulkill = flag.Bool("graceful-kill", false, "Gracefully attempt to kill the child process by sending a SIGTERM first")

	// initialized in main() due to custom type.
	flag_excludedDirs  globList
	flag_excludedFiles globList
	flag_includedFiles globList
)

func okColor(format string, args ...interface{}) string {
	if *flag_color {
		return color.GreenString(format, args...)
	} else {
		return fmt.Sprintf(format, args...)
	}
}

func failColor(format string, args ...interface{}) string {
	if *flag_color {
		return color.RedString(format, args...)
	} else {
		return fmt.Sprintf(format, args...)
	}
}

// Run `go build` and print the output if something's gone wrong.
func build() bool {
	log.Println(okColor("Running build command!"))

	args := strings.Split(*flag_build, " ")
	if len(args) == 0 {
		// If the user has specified and empty then we are done.
		return true
	}

	cmd := exec.Command(args[0], args[1:]...)

	if *flag_build_dir != "" {
		cmd.Dir = *flag_build_dir
	} else {
		cmd.Dir = *flag_directory
	}

	output, err := cmd.CombinedOutput()

	if err == nil {
		log.Println(okColor("Build ok."))
	} else {
		log.Println(failColor("Error while building:\n"), failColor(string(output)))
	}

	return err == nil
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Accept build jobs and start building when there are no jobs rushing in.
// The inrush protection is WorkDelay milliseconds long, in this period
// every incoming job will reset the timer.
func builder(jobs <-chan string, buildStarted chan<- string, buildDone chan<- bool) {
	createThreshold := func() <-chan time.Time {
		return time.After(time.Duration(WorkDelay * time.Millisecond))
	}

	threshold := createThreshold()
	eventPath := ""

	for {
		select {
		case eventPath = <-jobs:
			threshold = createThreshold()
		case <-threshold:
			buildStarted <- eventPath
			buildDone <- build()
		}
	}
}

func logger(pipeChan <-chan io.ReadCloser) {
	dumper := func(pipe io.ReadCloser, prefix string) {
		reader := bufio.NewReader(pipe)

	readloop:
		for {
			line, err := reader.ReadString('\n')

			if err != nil {
				break readloop
			}

			if *flag_logprefix {
				log.Print(prefix, " ", line)
			} else {
				log.Print(line)
			}
		}
	}

	for {
		pipe := <-pipeChan
		go dumper(pipe, "stdout:")

		pipe = <-pipeChan
		go dumper(pipe, "stderr:")
	}
}

// Start the supplied command and return stdout and stderr pipes for logging.
func startCommand(command string) (cmd *exec.Cmd, stdout io.ReadCloser, stderr io.ReadCloser, err error) {
	args := strings.Split(command, " ")
	cmd = exec.Command(args[0], args[1:]...)

	if stdout, err = cmd.StdoutPipe(); err != nil {
		err = fmt.Errorf("can't get stdout pipe for command: %s", err)
		return
	}

	if stderr, err = cmd.StderrPipe(); err != nil {
		err = fmt.Errorf("can't get stderr pipe for command: %s", err)
		return
	}

	if err = cmd.Start(); err != nil {
		err = fmt.Errorf("can't start command: %s", err)
		return
	}

	return
}

// Run the command in the given string and restart it after
// a message was received on the buildDone channel.
func runner(commandTemplate string, buildStarted <-chan string, buildSuccess <-chan bool) {
	var currentProcess *os.Process
	pipeChan := make(chan io.ReadCloser)

	go logger(pipeChan)

	go func() {
		sigChan := make(chan os.Signal, 1)
		signal.Notify(sigChan, fatalSignals...)
		<-sigChan
		log.Println(okColor("Received signal, terminating cleanly."))
		if currentProcess != nil {
			killProcess(currentProcess)
		}
		os.Exit(0)
	}()

	for {
		eventPath := <-buildStarted

		// append %0.s to use format specifier even if not supplied by user
		// to suppress warning in returned string.
		command := fmt.Sprintf("%0.s" + commandTemplate, eventPath)

		if !*flag_command_stop {
			if !<-buildSuccess {
				continue
			}
		}

		if currentProcess != nil {
			killProcess(currentProcess)
		}
		if *flag_command_stop {
			log.Println(okColor("Command stopped. Waiting for build to complete."))
			<-buildSuccess
		}

		log.Println(okColor("Restarting the given command."))
		cmd, stdoutPipe, stderrPipe, err := startCommand(command)

		if err != nil {
			log.Fatal(failColor("Could not start command: %s", err))
		}

		pipeChan <- stdoutPipe
		pipeChan <- stderrPipe

		currentProcess = cmd.Process
	}
}

func killProcess(process *os.Process) {
	if *flag_gracefulkill {
		killProcessGracefully(process)
	} else {
		killProcessHard(process)
	}
}

func killProcessHard(process *os.Process) {
	log.Println(okColor("Hard stopping the current process.."))

	if err := process.Kill(); err != nil {
		log.Fatal(failColor("Could not kill child process. Aborting due to danger of infinite forks."))
	}

	if _, err := process.Wait(); err != nil {
		log.Fatal(failColor("Could not wait for child process. Aborting due to danger of infinite forks."))
	}
}

func killProcessGracefully(process *os.Process) {
	done := make(chan error, 1)
	go func() {
		log.Println(okColor("Gracefully stopping the current process.."))
		if err := terminateGracefully(process); err != nil {
			done <- err
			return
		}
		_, err := process.Wait()
		done <- err
	}()

	select {
	case <-time.After(3 * time.Second):
		log.Println(failColor("Could not gracefully stop the current process, proceeding to hard stop."))
		killProcessHard(process)
		<-done
	case err := <-done:
		if err != nil {
			log.Fatal(failColor("Could not kill child process. Aborting due to danger of infinite forks."))
		}
	}
}

func flusher(buildStarted <-chan string, buildSuccess <-chan bool) {
	for {
		<-buildStarted
		<-buildSuccess
	}
}

func main() {
	flag.Var(&flag_excludedDirs, "exclude-dir", " Don't watch directories matching this name")
	flag.Var(&flag_excludedFiles, "exclude", " Don't watch files matching this name")
	flag.Var(&flag_includedFiles, "include", " Watch files matching this name")

	flag.Parse()

	if !*flag_logprefix {
		log.SetFlags(0)
	}

	if *flag_directory == "" {
		fmt.Fprintf(os.Stderr, "-directory=... is required.\n")
		os.Exit(1)
	}

	if *flag_gracefulkill && !gracefulTerminationPossible() {
		log.Fatal("Graceful termination is not supported on your platform.")
	}

	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if *flag_recursive == true {
		err = filepath.Walk(*flag_directory, func(path string, info os.FileInfo, err error) error {
			if err == nil && info.IsDir() {
				if flag_excludedDirs.Matches(info.Name()) {
					return filepath.SkipDir
				} else {
					return watcher.Add(path)
				}
			}
			return err
		})

		if err != nil {
			log.Fatal("filepath.Walk():", err)
		}

		if err := watcher.Add(*flag_directory); err != nil {
			log.Fatal("watcher.Add():", err)
		}

	} else {
		if err := watcher.Add(*flag_directory); err != nil {
			log.Fatal("watcher.Add():", err)
		}
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)
	buildSuccess := make(chan bool)
	buildStarted := make(chan string)

	go builder(jobs, buildStarted, buildSuccess)

	if *flag_command != "" {
		go runner(*flag_command, buildStarted, buildSuccess)
	} else {
		go flusher(buildStarted, buildSuccess)
	}

	for {
		select {
		case ev := <-watcher.Events:
			if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Write == fsnotify.Write || ev.Op&fsnotify.Create == fsnotify.Create {
				base := filepath.Base(ev.Name)

				// Assume it is a directory and track it.
				if *flag_recursive == true && !flag_excludedDirs.Matches(ev.Name) {
					watcher.Add(ev.Name)
				}

				if flag_includedFiles.Matches(base) || matchesPattern(pattern, ev.Name) {
					if !flag_excludedFiles.Matches(base) {
						jobs <- ev.Name
					}
				}
			}

		case err := <-watcher.Errors:
			if v, ok := err.(*os.SyscallError); ok {
				if v.Err == syscall.EINTR {
					continue
				}
				log.Fatal("watcher.Error: SyscallError:", v)
			}
			log.Fatal("watcher.Error:", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"
)

// Milliseconds to wait for the next job to begin after a file change
const WorkDelay = 900

// Default pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

var (
	flag_directory = flag.String("directory", ".", "Directory to watch for changes")
	flag_pattern   = flag.String("pattern", FilePattern, "Pattern of watched files")
	flag_command   = flag.String("command", "", "Command to run and restart after build")
	flag_recursive = flag.Bool("recursive", true, "Watch all dirs. recursively")
	flag_build     = flag.String("build", "go build", "Command to rebuild after changes")
)

// Run `go build` and print the output if something's gone wrong.
func build() bool {
	log.Println("Running build command!")

	args := strings.Split(*flag_build, " ")
	if len(args) == 0 {
		// If the user has specified and empty then we are done.
		return true
	}

	cmd := exec.Command(args[0], args[1:]...)

	cmd.Dir = *flag_directory

	output, err := cmd.CombinedOutput()

	if err == nil {
		log.Println("Build ok.")
	} else {
		log.Println("Error while building:\n", string(output))
	}

	return err == nil
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Accept build jobs and start building when there are no jobs rushing in.
// The inrush protection is WorkDelay milliseconds long, in this period
// every incoming job will reset the timer.
func builder(jobs <-chan string, buildDone chan<- bool) {
	createThreshold := func() <-chan time.Time {
		return time.After(time.Duration(WorkDelay * time.Millisecond))
	}

	threshold := createThreshold()

	for {
		select {
		case <-jobs:
			threshold = createThreshold()
		case <-threshold:
			if build() {
				buildDone <- true
			}
		}
	}
}

func logger(pipeChan <-chan io.ReadCloser) {
	dumper := func(pipe io.ReadCloser, prefix string) {
		reader := bufio.NewReader(pipe)

	readloop:
		for {
			line, err := reader.ReadString('\n')

			if err != nil {
				break readloop
			}

			log.Print(prefix, " ", line)
		}
	}

	for {
		pipe := <-pipeChan
		go dumper(pipe, "stdout:")

		pipe = <-pipeChan
		go dumper(pipe, "stderr:")
	}
}

// Start the supplied command and return stdout and stderr pipes for logging.
func startCommand(command string) (cmd *exec.Cmd, stdout io.ReadCloser, stderr io.ReadCloser, err error) {
	args := strings.Split(command, " ")
	cmd = exec.Command(args[0], args[1:]...)

	if stdout, err = cmd.StdoutPipe(); err != nil {
		err = fmt.Errorf("can't get stdout pipe for command: %s", err)
		return
	}

	if stderr, err = cmd.StderrPipe(); err != nil {
		err = fmt.Errorf("can't get stderr pipe for command: %s", err)
		return
	}

	if err = cmd.Start(); err != nil {
		err = fmt.Errorf("can't start command: %s", err)
		return
	}

	return
}

// Run the command in the given string and restart it after
// a message was received on the buildDone channel.
func runner(command string, buildDone chan bool) {
	var currentProcess *os.Process
	pipeChan := make(chan io.ReadCloser)

	go logger(pipeChan)

	for {
		<-buildDone

		if currentProcess != nil {
			if err := currentProcess.Kill(); err != nil {
				log.Fatal("Could not kill child process. Aborting due to danger of infinite forks.")
			}
		}

		log.Println("Restarting the given command.")
		cmd, stdoutPipe, stderrPipe, err := startCommand(command)

		if err != nil {
			log.Fatal("Could not start command:", err)
		}

		pipeChan <- stdoutPipe
		pipeChan <- stderrPipe

		currentProcess = cmd.Process
	}
}

func flusher(buildDone <-chan bool) {
	for {
		<-buildDone
	}
}

func main() {
	flag.Parse()

	if *flag_directory == "" {
		fmt.Fprintf(os.Stderr, "-directory=... is required.\n")
		os.Exit(1)
	}

	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if *flag_recursive == true {
		err = filepath.Walk(*flag_directory, func(path string, info os.FileInfo, err error) error {
			if err == nil && info.IsDir() {
				return watcher.Watch(path)
			}
			return err
		})

		if err != nil {
			log.Fatal("filepath.Walk():", err)
		}

	} else {
		err := watcher.Watch(*flag_directory)

		if err != nil {
			log.Fatal("watcher.Watch():", err)
		}
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)
	buildDone := make(chan bool)

	go builder(jobs, buildDone)

	if *flag_command != "" {
		go runner(*flag_command, buildDone)
	} else {
		go flusher(buildDone)
	}

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Name != "" && matchesPattern(pattern, ev.Name) {
				jobs <- ev.Name
			}

		case err := <-watcher.Error:
			if v, ok := err.(*os.SyscallError); ok {
				if v.Err == syscall.EINTR {
					continue
				}
				log.Fatal("watcher.Error: SyscallError:", v)
			}
			log.Fatal("watcher.Error:", err)
		}
	}
}
<commit_msg>Don't use up space in buildDone channel<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"
)

// Milliseconds to wait for the next job to begin after a file change
const WorkDelay = 900

// Default pattern to match files which trigger a build
const FilePattern = `(.+\.go|.+\.c)$`

var (
	flag_directory = flag.String("directory", ".", "Directory to watch for changes")
	flag_pattern   = flag.String("pattern", FilePattern, "Pattern of watched files")
	flag_command   = flag.String("command", "", "Command to run and restart after build")
	flag_recursive = flag.Bool("recursive", true, "Watch all dirs. recursively")
	flag_build     = flag.String("build", "go build", "Command to rebuild after changes")
)

// Run `go build` and print the output if something's gone wrong.
func build() bool {
	log.Println("Running build command!")

	args := strings.Split(*flag_build, " ")
	if len(args) == 0 {
		// If the user has specified and empty then we are done.
		return true
	}

	cmd := exec.Command(args[0], args[1:]...)

	cmd.Dir = *flag_directory

	output, err := cmd.CombinedOutput()

	if err == nil {
		log.Println("Build ok.")
	} else {
		log.Println("Error while building:\n", string(output))
	}

	return err == nil
}

func matchesPattern(pattern *regexp.Regexp, file string) bool {
	return pattern.MatchString(file)
}

// Accept build jobs and start building when there are no jobs rushing in.
// The inrush protection is WorkDelay milliseconds long, in this period
// every incoming job will reset the timer.
func builder(jobs <-chan string, buildDone chan<- struct{}) {
	createThreshold := func() <-chan time.Time {
		return time.After(time.Duration(WorkDelay * time.Millisecond))
	}

	threshold := createThreshold()

	for {
		select {
		case <-jobs:
			threshold = createThreshold()
		case <-threshold:
			if build() {
				buildDone <- struct{}{}
			}
		}
	}
}

func logger(pipeChan <-chan io.ReadCloser) {
	dumper := func(pipe io.ReadCloser, prefix string) {
		reader := bufio.NewReader(pipe)

	readloop:
		for {
			line, err := reader.ReadString('\n')

			if err != nil {
				break readloop
			}

			log.Print(prefix, " ", line)
		}
	}

	for {
		pipe := <-pipeChan
		go dumper(pipe, "stdout:")

		pipe = <-pipeChan
		go dumper(pipe, "stderr:")
	}
}

// Start the supplied command and return stdout and stderr pipes for logging.
func startCommand(command string) (cmd *exec.Cmd, stdout io.ReadCloser, stderr io.ReadCloser, err error) {
	args := strings.Split(command, " ")
	cmd = exec.Command(args[0], args[1:]...)

	if stdout, err = cmd.StdoutPipe(); err != nil {
		err = fmt.Errorf("can't get stdout pipe for command: %s", err)
		return
	}

	if stderr, err = cmd.StderrPipe(); err != nil {
		err = fmt.Errorf("can't get stderr pipe for command: %s", err)
		return
	}

	if err = cmd.Start(); err != nil {
		err = fmt.Errorf("can't start command: %s", err)
		return
	}

	return
}

// Run the command in the given string and restart it after
// a message was received on the buildDone channel.
func runner(command string, buildDone <-chan struct{}) {
	var currentProcess *os.Process
	pipeChan := make(chan io.ReadCloser)

	go logger(pipeChan)

	for {
		<-buildDone

		if currentProcess != nil {
			if err := currentProcess.Kill(); err != nil {
				log.Fatal("Could not kill child process. Aborting due to danger of infinite forks.")
			}
		}

		log.Println("Restarting the given command.")
		cmd, stdoutPipe, stderrPipe, err := startCommand(command)

		if err != nil {
			log.Fatal("Could not start command:", err)
		}

		pipeChan <- stdoutPipe
		pipeChan <- stderrPipe

		currentProcess = cmd.Process
	}
}

func flusher(buildDone <-chan struct{}) {
	for {
		<-buildDone
	}
}

func main() {
	flag.Parse()

	if *flag_directory == "" {
		fmt.Fprintf(os.Stderr, "-directory=... is required.\n")
		os.Exit(1)
	}

	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if *flag_recursive == true {
		err = filepath.Walk(*flag_directory, func(path string, info os.FileInfo, err error) error {
			if err == nil && info.IsDir() {
				return watcher.Watch(path)
			}
			return err
		})

		if err != nil {
			log.Fatal("filepath.Walk():", err)
		}

	} else {
		if err := watcher.Watch(*flag_directory); err != nil {
			log.Fatal("watcher.Watch():", err)
		}
	}

	pattern := regexp.MustCompile(*flag_pattern)
	jobs := make(chan string)
	buildDone := make(chan struct{})

	go builder(jobs, buildDone)

	if *flag_command != "" {
		go runner(*flag_command, buildDone)
	} else {
		go flusher(buildDone)
	}

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Name != "" && matchesPattern(pattern, ev.Name) {
				jobs <- ev.Name
			}

		case err := <-watcher.Error:
			if v, ok := err.(*os.SyscallError); ok {
				if v.Err == syscall.EINTR {
					continue
				}
				log.Fatal("watcher.Error: SyscallError:", v)
			}
			log.Fatal("watcher.Error:", err)
		}
	}
}
<|endoftext|>


<commit_before>package immortal

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	lock       uint32
	lock_defer uint32
	start      time.Time
	cmd        *exec.Cmd
}

func (self *Daemon) Process() *os.Process {
	return self.cmd.Process
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.lock, uint32(1)) != 0 {
		if self.cmd == nil {
			log.Printf("Service down")
		} else {
			log.Printf("PID %d (WANT IT DOWN) FIX THIS", self.cmd.Process.Pid)
			//log.Println("FIX THIS")
		}
		return
	}

	// Command to execute
	self.cmd = exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		self.cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		self.cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
			return
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
			return
		}

		// https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	// set the attributes
	self.cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		self.cmd.Stdout = w
		self.cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		self.cmd.Stdin = nil
		self.cmd.Stdout = nil
		self.cmd.Stderr = nil
	}

	// wait N seconds before starting
	if self.Wait > 0 {
		time.Sleep(time.Duration(self.Wait) * time.Second)
	}

	if err := self.cmd.Start(); err != nil {
		self.Control.state <- err
		return
	}

	// set start time
	self.start = time.Now()

	// write parent pid
	if self.Pid.Parent != "" {
		if err := self.WritePid(self.Pid.Parent, os.Getpid()); err != nil {
			log.Print(err)
		}
	}

	// write child pid
	if self.Pid.Child != "" {
		if err := self.WritePid(self.Pid.Child, self.cmd.Process.Pid); err != nil {
			log.Print(err)
		}
	}

	go func() {
		defer func() {
			if self.Logger.IsLogging() {
				w.Close()
			}
			// lock_defer defaults to 0, 1 to run only once/down (don't restart)
			atomic.StoreUint32(&self.lock, self.lock_defer)
		}()
		self.Control.state <- self.cmd.Wait()
	}()
}

func (self *Daemon) WritePid(file string, pid int) error {
	if err := ioutil.WriteFile(file, []byte(fmt.Sprintf("%d", pid)), 0644); err != nil {
		return err
	}
	return nil
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// create fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}

		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// read fifo
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<commit_msg>	modified:   daemon.go<commit_after>package immortal

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	lock       uint32
	lock_defer uint32
	start      time.Time
	cmd        *exec.Cmd
}

func (self *Daemon) Process() *os.Process {
	return self.cmd.Process
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.lock, uint32(1)) != 0 {
		return
	}

	// Command to execute
	self.cmd = exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		self.cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		self.cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
			return
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
			return
		}

		// https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	// set the attributes
	self.cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		self.cmd.Stdout = w
		self.cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		self.cmd.Stdin = nil
		self.cmd.Stdout = nil
		self.cmd.Stderr = nil
	}

	// wait N seconds before starting
	if self.Wait > 0 {
		time.Sleep(time.Duration(self.Wait) * time.Second)
	}

	if err := self.cmd.Start(); err != nil {
		self.Control.state <- err
		return
	}

	// set start time
	self.start = time.Now()

	// write parent pid
	if self.Pid.Parent != "" {
		if err := self.WritePid(self.Pid.Parent, os.Getpid()); err != nil {
			log.Print(err)
		}
	}

	// write child pid
	if self.Pid.Child != "" {
		if err := self.WritePid(self.Pid.Child, self.cmd.Process.Pid); err != nil {
			log.Print(err)
		}
	}

	go func() {
		defer func() {
			if self.Logger.IsLogging() {
				w.Close()
			}
			// lock_defer defaults to 0, 1 to run only once/down (don't restart)
			atomic.StoreUint32(&self.lock, self.lock_defer)
		}()
		self.Control.state <- self.cmd.Wait()
	}()
}

func (self *Daemon) WritePid(file string, pid int) error {
	if err := ioutil.WriteFile(file, []byte(fmt.Sprintf("%d", pid)), 0644); err != nil {
		return err
	}
	return nil
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// create fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}

		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// read fifo
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<|endoftext|>


<commit_before>package miner

import (
	"github.com/ethereum/ethash"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
)

type RemoteAgent struct {
	work        *types.Block
	currentWork *types.Block

	quit     chan struct{}
	workCh   chan *types.Block
	returnCh chan<- *types.Block
}

func NewRemoteAgent() *RemoteAgent {
	agent := &RemoteAgent{}

	return agent
}

func (a *RemoteAgent) Work() chan<- *types.Block {
	return a.workCh
}

func (a *RemoteAgent) SetReturnCh(returnCh chan<- *types.Block) {
	a.returnCh = returnCh
}

func (a *RemoteAgent) Start() {
	a.quit = make(chan struct{})
	a.workCh = make(chan *types.Block, 1)
	go a.run()
}

func (a *RemoteAgent) Stop() {
	close(a.quit)
	close(a.workCh)
}

func (a *RemoteAgent) GetHashRate() int64 { return 0 }

func (a *RemoteAgent) run() {
out:
	for {
		select {
		case <-a.quit:
			break out
		case work := <-a.workCh:
			a.work = work
			a.returnCh <- nil
		}
	}
}

func (a *RemoteAgent) GetWork() [3]string {
	var res [3]string

	// XXX Wait here until work != nil ?
	if a.work != nil {
		res[0] = a.work.HashNoNonce().Hex()
		seedHash, _ := ethash.GetSeedHash(a.currentWork.NumberU64())
		res[1] = common.Bytes2Hex(seedHash)
		res[2] = common.Bytes2Hex(a.work.Difficulty().Bytes())
	}

	return res
}

func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, seedHash common.Hash) bool {
	// Return true or false, but does not indicate if the PoW was correct

	// Make sure the external miner was working on the right hash
	if a.currentWork != nil && a.work != nil {
		a.currentWork.SetNonce(nonce)
		a.currentWork.Header().MixDigest = mixDigest
		a.returnCh <- a.currentWork
		//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
		return true
	}

	return false
}
<commit_msg>miner: fixed remote miner current work<commit_after>package miner

import (
	"github.com/ethereum/ethash"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
)

type RemoteAgent struct {
	work        *types.Block
	currentWork *types.Block

	quit     chan struct{}
	workCh   chan *types.Block
	returnCh chan<- *types.Block
}

func NewRemoteAgent() *RemoteAgent {
	agent := &RemoteAgent{}

	return agent
}

func (a *RemoteAgent) Work() chan<- *types.Block {
	return a.workCh
}

func (a *RemoteAgent) SetReturnCh(returnCh chan<- *types.Block) {
	a.returnCh = returnCh
}

func (a *RemoteAgent) Start() {
	a.quit = make(chan struct{})
	a.workCh = make(chan *types.Block, 1)
	go a.run()
}

func (a *RemoteAgent) Stop() {
	close(a.quit)
	close(a.workCh)
}

func (a *RemoteAgent) GetHashRate() int64 { return 0 }

func (a *RemoteAgent) run() {
out:
	for {
		select {
		case <-a.quit:
			break out
		case work := <-a.workCh:
			a.work = work
		}
	}
}

func (a *RemoteAgent) GetWork() [3]string {
	var res [3]string

	// XXX Wait here until work != nil ?
	if a.work != nil {
		a.currentWork = a.work

		res[0] = a.work.HashNoNonce().Hex()
		seedHash, _ := ethash.GetSeedHash(a.currentWork.NumberU64())
		res[1] = common.Bytes2Hex(seedHash)
		res[2] = common.Bytes2Hex(a.work.Difficulty().Bytes())
	}

	return res
}

func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, seedHash common.Hash) bool {
	// Return true or false, but does not indicate if the PoW was correct

	// Make sure the external miner was working on the right hash
	if a.currentWork != nil && a.work != nil {
		a.currentWork.SetNonce(nonce)
		a.currentWork.Header().MixDigest = mixDigest
		a.returnCh <- a.currentWork
		//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
		return true
	}

	return false
}
<|endoftext|>