<commit_before>package goose

import (
	"container/list"
	"github.com/advancedlogic/goquery"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"log"
	"regexp"
	"strings"
)

// Cleaner removes menus, ads, sidebars, etc. and leaves the main content
type Cleaner struct {
	config Configuration
}

// NewCleaner returns a new instance of a Cleaner
func NewCleaner(config Configuration) Cleaner {
	return Cleaner{
		config: config,
	}
}

var divToPElementsPattern = regexp.MustCompile("<(a|blockquote|dl|div|img|ol|p|pre|table|ul)")
var tabsRegEx, _ = regexp.Compile("\\t|^\\s+$]")
var removeNodesRegEx = regexp.MustCompile("" +
	"PopularQuestions|" +
	"[Cc]omentario|" +
	"[Ff]ooter|" +
	"^fn$|" +
	"^inset$|" +
	"^print$|" +
	"^scroll$|" +
	"^side$|" +
	"^side_|" +
	"^widget$|" +
	"ajoutVideo|" +
	"articleheadings|" +
	"author-dropdown|" +
	"blog-pager|" +
	"breadcrumbs|" +
	"byline|" +
	"cabecalho|" +
	"cnnStryHghLght|" +
	"cnn_html_slideshow|" +
	"cnn_strycaptiontxt|" +
	"cnn_strylftcntnt|" +
	"cnn_stryspcvbx|" +
	"combx|" +
	"comment|" +
	"communitypromo|" +
	"contact|" +
	"contentTools2|" +
	"controls|" +
	"^date$|" +
	"detail_new_|" +
	"detail_related_|" +
	"figcaption|" +
	"footnote|" +
	"foot|" +
	"header|" +
	"img_popup_single|" +
	"js_replies|" +
	"[Kk]ona[Ff]ilter|" +
	"leading|" +
	"legende|" +
	"links|" +
	"mediaarticlerelated|" +
	"menucontainer|" +
	"meta$|" +
	"navbar|" +
	"pagetools|" +
	"popup|" +
	"post-attributes|" +
	"post-title|" +
	"relacionado|" +
	"retweet|" +
	"runaroundLeft|" +
	"shoutbox|" +
	"site_nav|" +
	"socialNetworking|" +
	"social_|" +
	"socialnetworking|" +
	"socialtools|" +
	"sponsor|" +
	"sub_nav|" +
	"subscribe|" +
	"tag_|" +
	"tags|" +
	"the_answers|" +
	"timestamp|" +
	"tools|" +
	"vcard|" +
	"welcome_form|" +
	"wp-caption-text")
var captionsRegEx = regexp.MustCompile("^caption$")
var googleRegEx = regexp.MustCompile(" google ")
var moreRegEx = regexp.MustCompile("^[^entry-]more.*$")
var facebookRegEx = regexp.MustCompile("[^-]facebook")
var facebookBroadcastingRegEx = regexp.MustCompile("facebook-broadcasting")
var twitterRegEx = regexp.MustCompile("[^-]twitter")

func (c *Cleaner) clean(article *Article) *goquery.Document {
	if c.config.debug {
		log.Println("Starting cleaning phase with Cleaner")
	}
	docToClean := article.Doc
	docToClean = c.cleanArticleTags(docToClean)
	docToClean = c.cleanEMTags(docToClean)
	docToClean = c.dropCaps(docToClean)
	docToClean = c.removeScriptsStyle(docToClean)
	docToClean = c.cleanBadTags(docToClean)
	docToClean = c.cleanFooter(docToClean)
	docToClean = c.cleanAside(docToClean)
	docToClean = c.removeNodesRegEx(docToClean, captionsRegEx)
	docToClean = c.removeNodesRegEx(docToClean, googleRegEx)
	docToClean = c.removeNodesRegEx(docToClean, moreRegEx)
	docToClean = c.removeNodesRegEx(docToClean, facebookRegEx)
	docToClean = c.removeNodesRegEx(docToClean, facebookBroadcastingRegEx)
	docToClean = c.removeNodesRegEx(docToClean, twitterRegEx)
	docToClean = c.cleanParaSpans(docToClean)

	docToClean = c.convertDivsToParagraphs(docToClean, "div")
	docToClean = c.convertDivsToParagraphs(docToClean, "span")
	docToClean = c.convertDivsToParagraphs(docToClean, "article")
	docToClean = c.convertDivsToParagraphs(docToClean, "pre")

	return docToClean
}

func (c *Cleaner) cleanArticleTags(doc *goquery.Document) *goquery.Document {
	tags := [3]string{"id", "name", "class"}
	articles := doc.Find("article")
	articles.Each(func(i int, s *goquery.Selection) {
		for _, tag := range tags {
			c.config.parser.delAttr(s, tag)
		}
	})
	return doc
}

func (c *Cleaner) cleanEMTags(doc *goquery.Document) *goquery.Document {
	ems := doc.Find("em")
	ems.Each(func(i int, s *goquery.Selection) {
		images := s.Find("img")
		if images.Length() == 0 {
			c.config.parser.dropTag(s)
		}
	})
	if c.config.debug {
		log.Printf("Cleaning %d EM tags\n", ems.Size())
	}
	return doc
}

func (c *Cleaner) cleanFooter(doc *goquery.Document) *goquery.Document {
	footer := doc.Find("footer")
	footer.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanAside(doc *goquery.Document) *goquery.Document {
	aside := doc.Find("aside")
	aside.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanCites(doc *goquery.Document) *goquery.Document {
	cites := doc.Find("cite")
	cites.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanDivs(doc *goquery.Document) *goquery.Document {
	frames := make(map[string]int)
	framesNodes := make(map[string]*list.List)
	divs := doc.Find("div")
	divs.Each(func(i int, s *goquery.Selection) {
		children := s.Children()
		if children.Size() == 0 {
			text := s.Text()
			text = strings.Trim(text, " ")
			text = strings.Trim(text, "\t")
			text = strings.ToLower(text)
			frames[text]++
			if framesNodes[text] == nil {
				framesNodes[text] = list.New()
			}
			framesNodes[text].PushBack(s)
		}
	})
	for text, freq := range frames {
		if freq > 1 {
			selections := framesNodes[text]
			for s := selections.Front(); s != nil; s = s.Next() {
				selection := s.Value.(*goquery.Selection)
				c.config.parser.removeNode(selection)
			}
		}
	}
	return doc
}

func (c *Cleaner) dropCaps(doc *goquery.Document) *goquery.Document {
	items := doc.Find("span")
	count := 0 //remove
	items.Each(func(i int, s *goquery.Selection) {
		attribute, exists := s.Attr("class")
		if exists && (strings.Contains(attribute, "dropcap") || strings.Contains(attribute, "drop_cap")) {
			count++
			c.config.parser.dropTag(s)
		}
	})
	if c.config.debug {
		log.Printf("Cleaning %d dropcap tags\n", count)
	}
	return doc
}

func (c *Cleaner) removeScriptsStyle(doc *goquery.Document) *goquery.Document {
	if c.config.debug {
		log.Println("Starting to remove script tags")
	}
	scripts := doc.Find("script,noscript,style")
	scripts.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	if c.config.debug {
		log.Printf("Removed %d script and style tags\n", scripts.Size())
	}

	//remove comments :) How????
	return doc
}

func (c *Cleaner) matchNodeRegEx(attribute string, pattern *regexp.Regexp) bool {
	return pattern.MatchString(attribute)
}

func (c *Cleaner) removeNodesRegEx(doc *goquery.Document, pattern *regexp.Regexp) *goquery.Document {
	selectors := [3]string{"id", "class", "name"}
	for _, selector := range selectors {
		naughtyList := doc.Find("*[" + selector + "]")
		cont := 0
		naughtyList.Each(func(i int, s *goquery.Selection) {
			attribute, _ := s.Attr(selector)
			if c.matchNodeRegEx(attribute, pattern) {
				cont++
				c.config.parser.removeNode(s)
			}
		})

		if c.config.debug {
			log.Printf("regExRemoveNodes %d %s elements found against pattern %s\n", cont, selector, pattern.String())
		}
	}
	return doc
}

func (c *Cleaner) cleanBadTags(doc *goquery.Document) *goquery.Document {
	body := doc.Find("body")
	children := body.Children()
	selectors := []string{"id", "class", "name"}
	for _, selector := range selectors {
		children.Each(func(i int, s *goquery.Selection) {
			naughtyList := s.Find("*[" + selector + "]")
			cont := 0
			naughtyList.Each(func(j int, e *goquery.Selection) {
				attribute, _ := e.Attr(selector)
				if c.matchNodeRegEx(attribute, removeNodesRegEx) {
					if c.config.debug {

						log.Printf("Cleaning: Removing node with %s: %s\n", selector, c.config.parser.name(selector, e))
					}
					c.config.parser.removeNode(e)
					cont++
				}
			})
			if c.config.debug && cont > 0 {
				log.Printf("%d naughty %s elements found", cont, selector)
			}
		})
	}
	return doc
}

func (c *Cleaner) cleanParaSpans(doc *goquery.Document) *goquery.Document {
	spans := doc.Find("span")
	spans.Each(func(i int, s *goquery.Selection) {
		parent := s.Parent()
		if parent != nil && parent.Length() > 0 && parent.Get(0).DataAtom == atom.P {
			node := s.Get(0)
			node.Data = s.Text()
			node.Type = html.TextNode
		}
	})
	return doc
}

func (c *Cleaner) getFlushedBuffer(fragment string) []*html.Node {
	var output []*html.Node
	reader := strings.NewReader(fragment)
	document, _ := html.Parse(reader)
	body := document.FirstChild.LastChild
	for c := body.FirstChild; c != nil; c = c.NextSibling {
		output = append(output, c)
		c.Parent = nil
		c.PrevSibling = nil
	}

	for _, o := range output {
		o.NextSibling = nil
	}
	return output
}

func (c *Cleaner) replaceWithPara(div *goquery.Selection) {
	if div.Size() > 0 {
		node := div.Get(0)
		node.Data = atom.P.String()
		node.DataAtom = atom.P
	}
}

func (c *Cleaner) tabsAndNewLinesReplacements(text string) string {
	text = strings.Replace(text, "\n", "\n\n", -1)
	text = tabsRegEx.ReplaceAllString(text, "")
	return text
}

func (c *Cleaner) convertDivsToParagraphs(doc *goquery.Document, domType string) *goquery.Document {
	if c.config.debug {
		log.Println("Starting to replace bad divs...")
	}
	badDivs := 0
	convertedTextNodes := 0
	divs := doc.Find(domType)

	divs.Each(func(i int, div *goquery.Selection) {
		divHTML, _ := div.Html()
		if divToPElementsPattern.Match([]byte(divHTML)) {
			c.replaceWithPara(div)
			badDivs++
		} else {
			var replacementText []string
			nodesToRemove := list.New()
			children := div.Contents()
			if c.config.debug {
				log.Printf("Found %d children of div\n", children.Size())
			}
			children.EachWithBreak(func(i int, kid *goquery.Selection) bool {
				text := kid.Text()
				kidNode := kid.Get(0)
				tag := kidNode.Data
				if tag == text {
					tag = "#text"
				}
				if tag == "#text" {
					text = strings.Replace(text, "\n", "", -1)
					text = tabsRegEx.ReplaceAllString(text, "")
					if text == "" {
						return true
					}
					if len(text) > 1 {
						prev := kidNode.PrevSibling
						if c.config.debug {
							log.Printf("PARENT CLASS: %s NODENAME: %s\n", c.config.parser.name("class", div), tag)
							log.Printf("TEXTREPLACE: %s\n", strings.Replace(text, "\n", "", -1))
						}
						if prev != nil && prev.DataAtom == atom.A {
							nodeSelection := kid.HasNodes(prev)
							html, _ := nodeSelection.Html()
							replacementText = append(replacementText, html)
							if c.config.debug {
								log.Printf("SIBLING NODENAME ADDITION: %s TEXT: %s\n", prev.Data, html)
							}
						}
						replacementText = append(replacementText, text)
						nodesToRemove.PushBack(kidNode)
						convertedTextNodes++
					}

				}
				return true
			})

			newNode := new(html.Node)
			newNode.Type = html.ElementNode
			newNode.Data = strings.Join(replacementText, "")
			newNode.DataAtom = atom.P
			div.First().AddNodes(newNode)

			for s := nodesToRemove.Front(); s != nil; s = s.Next() {
				node := s.Value.(*html.Node)
				if node != nil && node.Parent != nil {
					node.Parent.RemoveChild(node)
				}
			}
		}
	})
	if c.config.debug {
		log.Printf("Found %d total divs with %d bad divs replaced and %d textnodes converted inside divs", divs.Size(), badDivs, convertedTextNodes)
	}
	return doc

}
<commit_msg>DEV-4442 new cleaning classes<commit_after>package goose

import (
	"container/list"
	"github.com/advancedlogic/goquery"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"log"
	"regexp"
	"strings"
)

// Cleaner removes menus, ads, sidebars, etc. and leaves the main content
type Cleaner struct {
	config Configuration
}

// NewCleaner returns a new instance of a Cleaner
func NewCleaner(config Configuration) Cleaner {
	return Cleaner{
		config: config,
	}
}

var divToPElementsPattern = regexp.MustCompile("<(a|blockquote|dl|div|img|ol|p|pre|table|ul)")
var tabsRegEx, _ = regexp.Compile("\\t|^\\s+$]")
var removeNodesRegEx = regexp.MustCompile("" +
	"PopularQuestions|" +
	"[Cc]omentario|" +
	"[Ff]ooter|" +
	"^fn$|" +
	"^inset$|" +
	"^print$|" +
	"^scroll$|" +
	"^side$|" +
	"^side_|" +
	"^widget$|" +
	"ajoutVideo|" +
	"articleheadings|" +
	"_articles|" +
	"author|" +
	"author-dropdown|" +
	"banner|" +
	"^bar$|" +
	"blog-pager|" +
	"breadcrumbs|" +
	"byline|" +
	"cabecalho|" +
	"carousel|" +
	"cnnStryHghLght|" +
	"cnn_html_slideshow|" +
	"cnn_strycaptiontxt|" +
	"cnn_strylftcntnt|" +
	"cnn_stryspcvbx|" +
	"combx|" +
	"comment|" +
	"communitypromo|" +
	"contact|" +
	"contentTools2|" +
	"controls|" +
	"cookie|" +
	"^date$|" +
	"detail_new_|" +
	"detail_related_|" +
	"figcaption|" +
	"footnote|" +
	"foot|" +
	"header|" +
	"img_popup_single|" +
	"js_replies|" +
	"[Kk]ona[Ff]ilter|" +
	"leading|" +
	"legend|" +
	"legende|" +
	"links|" +
	"mediaarticlerelated|" +
	"menu|" +
	"menucontainer|" +
	"meta$|" +
	"moreNews|" +
	"navbar|" +
	"newsUnder|" +
	"panelss2|" +
	"panesCity|" +
	"pagetools|" +
	"popup|" +
	"post-attributes|" +
	"post-title|" +
	"relacionado|" +
	"retweet|" +
	"rightBlock|" +
	"rss|" +
	"runaroundLeft|" +
	"shoutbox|" +
	"site_box|" +
	"site_nav|" +
	"socialNetworking|" +
	"social_|" +
	"socialnetworking|" +
	"socialtools|" +
	"source|" +
	"sponsor|" +
	"sub_nav|" +
	"subscribe|" +
	"tabsCity|" +
	"tag_|" +
	"tags|" +
	"teaser|" +
	"the_answers|" +
	"timestamp|" +
	"tools|" +
	"vcard|" +
	"welcome_form|" +
	"wp-caption-text")

var captionsRegEx = regexp.MustCompile("^caption$")
var googleRegEx = regexp.MustCompile(" google ")
var moreRegEx = regexp.MustCompile("^[^entry-]more.*$")
var facebookRegEx = regexp.MustCompile("[^-]facebook")
var facebookBroadcastingRegEx = regexp.MustCompile("facebook-broadcasting")
var twitterRegEx = regexp.MustCompile("[^-]twitter")

func (c *Cleaner) clean(article *Article) *goquery.Document {
	if c.config.debug {
		log.Println("Starting cleaning phase with Cleaner")
	}
	docToClean := article.Doc
	docToClean = c.cleanArticleTags(docToClean)
	docToClean = c.cleanEMTags(docToClean)
	docToClean = c.dropCaps(docToClean)
	docToClean = c.removeScriptsStyle(docToClean)
	docToClean = c.cleanBadTags(docToClean)
	docToClean = c.cleanFooter(docToClean)
	docToClean = c.cleanAside(docToClean)
	docToClean = c.removeNodesRegEx(docToClean, captionsRegEx)
	docToClean = c.removeNodesRegEx(docToClean, googleRegEx)
	docToClean = c.removeNodesRegEx(docToClean, moreRegEx)
	docToClean = c.removeNodesRegEx(docToClean, facebookRegEx)
	docToClean = c.removeNodesRegEx(docToClean, facebookBroadcastingRegEx)
	docToClean = c.removeNodesRegEx(docToClean, twitterRegEx)
	docToClean = c.cleanParaSpans(docToClean)

	docToClean = c.convertDivsToParagraphs(docToClean, "div")
	docToClean = c.convertDivsToParagraphs(docToClean, "span")
	docToClean = c.convertDivsToParagraphs(docToClean, "article")
	docToClean = c.convertDivsToParagraphs(docToClean, "pre")

	return docToClean
}

func (c *Cleaner) cleanArticleTags(doc *goquery.Document) *goquery.Document {
	tags := [3]string{"id", "name", "class"}
	articles := doc.Find("article")
	articles.Each(func(i int, s *goquery.Selection) {
		for _, tag := range tags {
			c.config.parser.delAttr(s, tag)
		}
	})
	return doc
}

func (c *Cleaner) cleanEMTags(doc *goquery.Document) *goquery.Document {
	ems := doc.Find("em")
	ems.Each(func(i int, s *goquery.Selection) {
		images := s.Find("img")
		if images.Length() == 0 {
			c.config.parser.dropTag(s)
		}
	})
	if c.config.debug {
		log.Printf("Cleaning %d EM tags\n", ems.Size())
	}
	return doc
}

func (c *Cleaner) cleanFooter(doc *goquery.Document) *goquery.Document {
	footer := doc.Find("footer")
	footer.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanAside(doc *goquery.Document) *goquery.Document {
	aside := doc.Find("aside")
	aside.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanCites(doc *goquery.Document) *goquery.Document {
	cites := doc.Find("cite")
	cites.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	return doc
}

func (c *Cleaner) cleanDivs(doc *goquery.Document) *goquery.Document {
	frames := make(map[string]int)
	framesNodes := make(map[string]*list.List)
	divs := doc.Find("div")
	divs.Each(func(i int, s *goquery.Selection) {
		children := s.Children()
		if children.Size() == 0 {
			text := s.Text()
			text = strings.Trim(text, " ")
			text = strings.Trim(text, "\t")
			text = strings.ToLower(text)
			frames[text]++
			if framesNodes[text] == nil {
				framesNodes[text] = list.New()
			}
			framesNodes[text].PushBack(s)
		}
	})
	for text, freq := range frames {
		if freq > 1 {
			selections := framesNodes[text]
			for s := selections.Front(); s != nil; s = s.Next() {
				selection := s.Value.(*goquery.Selection)
				c.config.parser.removeNode(selection)
			}
		}
	}
	return doc
}

func (c *Cleaner) dropCaps(doc *goquery.Document) *goquery.Document {
	items := doc.Find("span")
	count := 0 //remove
	items.Each(func(i int, s *goquery.Selection) {
		attribute, exists := s.Attr("class")
		if exists && (strings.Contains(attribute, "dropcap") || strings.Contains(attribute, "drop_cap")) {
			count++
			c.config.parser.dropTag(s)
		}
	})
	if c.config.debug {
		log.Printf("Cleaning %d dropcap tags\n", count)
	}
	return doc
}

func (c *Cleaner) removeScriptsStyle(doc *goquery.Document) *goquery.Document {
	if c.config.debug {
		log.Println("Starting to remove script tags")
	}
	scripts := doc.Find("script,noscript,style")
	scripts.Each(func(i int, s *goquery.Selection) {
		c.config.parser.removeNode(s)
	})
	if c.config.debug {
		log.Printf("Removed %d script and style tags\n", scripts.Size())
	}

	//remove comments :) How????
	return doc
}

func (c *Cleaner) matchNodeRegEx(attribute string, pattern *regexp.Regexp) bool {
	return pattern.MatchString(attribute)
}

func (c *Cleaner) removeNodesRegEx(doc *goquery.Document, pattern *regexp.Regexp) *goquery.Document {
	selectors := [3]string{"id", "class", "name"}
	for _, selector := range selectors {
		naughtyList := doc.Find("*[" + selector + "]")
		cont := 0
		naughtyList.Each(func(i int, s *goquery.Selection) {
			attribute, _ := s.Attr(selector)
			if c.matchNodeRegEx(attribute, pattern) {
				cont++
				c.config.parser.removeNode(s)
			}
		})

		if c.config.debug {
			log.Printf("regExRemoveNodes %d %s elements found against pattern %s\n", cont, selector, pattern.String())
		}
	}
	return doc
}

func (c *Cleaner) cleanBadTags(doc *goquery.Document) *goquery.Document {
	body := doc.Find("body")
	children := body.Children()
	selectors := []string{"id", "class", "name"}
	for _, selector := range selectors {
		children.Each(func(i int, s *goquery.Selection) {
			naughtyList := s.Find("*[" + selector + "]")
			cont := 0
			naughtyList.Each(func(j int, e *goquery.Selection) {
				attribute, _ := e.Attr(selector)
				if c.matchNodeRegEx(attribute, removeNodesRegEx) {
					if c.config.debug {

						log.Printf("Cleaning: Removing node with %s: %s\n", selector, c.config.parser.name(selector, e))
					}
					c.config.parser.removeNode(e)
					cont++
				}
			})
			if c.config.debug && cont > 0 {
				log.Printf("%d naughty %s elements found", cont, selector)
			}
		})
	}
	return doc
}

func (c *Cleaner) cleanParaSpans(doc *goquery.Document) *goquery.Document {
	spans := doc.Find("span")
	spans.Each(func(i int, s *goquery.Selection) {
		parent := s.Parent()
		if parent != nil && parent.Length() > 0 && parent.Get(0).DataAtom == atom.P {
			node := s.Get(0)
			node.Data = s.Text()
			node.Type = html.TextNode
		}
	})
	return doc
}

func (c *Cleaner) getFlushedBuffer(fragment string) []*html.Node {
	var output []*html.Node
	reader := strings.NewReader(fragment)
	document, _ := html.Parse(reader)
	body := document.FirstChild.LastChild
	for c := body.FirstChild; c != nil; c = c.NextSibling {
		output = append(output, c)
		c.Parent = nil
		c.PrevSibling = nil
	}

	for _, o := range output {
		o.NextSibling = nil
	}
	return output
}

func (c *Cleaner) replaceWithPara(div *goquery.Selection) {
	if div.Size() > 0 {
		node := div.Get(0)
		node.Data = atom.P.String()
		node.DataAtom = atom.P
	}
}

func (c *Cleaner) tabsAndNewLinesReplacements(text string) string {
	text = strings.Replace(text, "\n", "\n\n", -1)
	text = tabsRegEx.ReplaceAllString(text, "")
	return text
}

func (c *Cleaner) convertDivsToParagraphs(doc *goquery.Document, domType string) *goquery.Document {
	if c.config.debug {
		log.Println("Starting to replace bad divs...")
	}
	badDivs := 0
	convertedTextNodes := 0
	divs := doc.Find(domType)

	divs.Each(func(i int, div *goquery.Selection) {
		divHTML, _ := div.Html()
		if divToPElementsPattern.Match([]byte(divHTML)) {
			c.replaceWithPara(div)
			badDivs++
		} else {
			var replacementText []string
			nodesToRemove := list.New()
			children := div.Contents()
			if c.config.debug {
				log.Printf("Found %d children of div\n", children.Size())
			}
			children.EachWithBreak(func(i int, kid *goquery.Selection) bool {
				text := kid.Text()
				kidNode := kid.Get(0)
				tag := kidNode.Data
				if tag == text {
					tag = "#text"
				}
				if tag == "#text" {
					text = strings.Replace(text, "\n", "", -1)
					text = tabsRegEx.ReplaceAllString(text, "")
					if text == "" {
						return true
					}
					if len(text) > 1 {
						prev := kidNode.PrevSibling
						if c.config.debug {
							log.Printf("PARENT CLASS: %s NODENAME: %s\n", c.config.parser.name("class", div), tag)
							log.Printf("TEXTREPLACE: %s\n", strings.Replace(text, "\n", "", -1))
						}
						if prev != nil && prev.DataAtom == atom.A {
							nodeSelection := kid.HasNodes(prev)
							html, _ := nodeSelection.Html()
							replacementText = append(replacementText, html)
							if c.config.debug {
								log.Printf("SIBLING NODENAME ADDITION: %s TEXT: %s\n", prev.Data, html)
							}
						}
						replacementText = append(replacementText, text)
						nodesToRemove.PushBack(kidNode)
						convertedTextNodes++
					}

				}
				return true
			})

			newNode := new(html.Node)
			newNode.Type = html.ElementNode
			newNode.Data = strings.Join(replacementText, "")
			newNode.DataAtom = atom.P
			div.First().AddNodes(newNode)

			for s := nodesToRemove.Front(); s != nil; s = s.Next() {
				node := s.Value.(*html.Node)
				if node != nil && node.Parent != nil {
					node.Parent.RemoveChild(node)
				}
			}
		}
	})
	if c.config.debug {
		log.Printf("Found %d total divs with %d bad divs replaced and %d textnodes converted inside divs", divs.Size(), badDivs, convertedTextNodes)
	}
	return doc

}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/chzyer/readline"
	"github.com/jamesnetherton/homehub-cli/cmd"
	"github.com/jamesnetherton/homehub-cli/service"
)

// CLI is a representation of the home hub command line interface
type CLI struct {
	readline *readline.Instance
	commands []cmd.Command
}

// NewCLI creates a new CLI
func NewCLI(commands []cmd.Command, readLine *readline.Instance) (cli *CLI) {
	c := &CLI{
		readLine,
		commands,
	}

	c.readline.Config.AutoComplete = readline.NewPrefixCompleter(readline.PcItemDynamic(c.commandListFunction()))

	return c
}

// Run starts the CLI and processes user input
func (c *CLI) Run() {
	defer c.readline.Close()

	banner()

	for {
		line, err := c.readline.Readline()
		if err == readline.ErrInterrupt {
			if len(line) == 0 {
				break
			} else {
				continue
			}
		} else if err == io.EOF {
			break
		}

		line = strings.TrimSpace(line)
		if !service.StringIsEmpty(line) {
			commandLine := strings.Split(line, " ")
			commandName := commandLine[0]

			command := c.findCommand(commandName)
			if command != nil {
				args := append(commandLine[:0], commandLine[1:]...)
				command.ExecuteLifecylce(args)
			} else {
				fmt.Println("homehub: Command not found:", strconv.Quote(commandName))
			}
		}
	}
}

func (c *CLI) findCommand(commandName string) (command cmd.Command) {
	for i := 0; i < len(c.commands); i++ {
		if c.commands[i].GetName() == commandName {
			return c.commands[i]
		}
	}
	return nil
}

func (c *CLI) commandListFunction() func(string) []string {
	return func(s string) []string {
		var commands []string
		for i := 0; i < len(c.commands); i++ {
			commands = append(commands, c.commands[i].GetName())
		}
		return commands
	}
}

func banner() {
	fmt.Println(" _   _                           _   _         _")
	fmt.Println("| | | |                         | | | |       | |")
	fmt.Println("| |_| |  ___   _ __ ___    ___  | |_| | _   _ | |__")
	fmt.Println("|  _  | / _ \\ | '_ ` _ \\  / _ \\ |  _  || | | || '_ \\")
	fmt.Println("| | | || (_) || | | | | ||  __/ | | | || |_| || |_) |")
	fmt.Println("\\_| |_/ \\___/ |_| |_| |_| \\___| \\_| |_/ \\__,_||_.__/")
	fmt.Printf("\n=====================================================\n\n")
}
<commit_msg>Prevent CLI exiting on ctrl+c<commit_after>package cli

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/chzyer/readline"
	"github.com/jamesnetherton/homehub-cli/cmd"
	"github.com/jamesnetherton/homehub-cli/service"
)

// CLI is a representation of the home hub command line interface
type CLI struct {
	readline *readline.Instance
	commands []cmd.Command
}

// NewCLI creates a new CLI
func NewCLI(commands []cmd.Command, readLine *readline.Instance) (cli *CLI) {
	c := &CLI{
		readLine,
		commands,
	}

	c.readline.Config.AutoComplete = readline.NewPrefixCompleter(readline.PcItemDynamic(c.commandListFunction()))

	return c
}

// Run starts the CLI and processes user input
func (c *CLI) Run() {
	defer c.readline.Close()

	banner()

	for {
		line, err := c.readline.Readline()
		if err == readline.ErrInterrupt {
			continue
		} else if err == io.EOF {
			break
		}

		line = strings.TrimSpace(line)
		if !service.StringIsEmpty(line) {
			commandLine := strings.Split(line, " ")
			commandName := commandLine[0]

			command := c.findCommand(commandName)
			if command != nil {
				args := append(commandLine[:0], commandLine[1:]...)
				command.ExecuteLifecylce(args)
			} else {
				fmt.Println("homehub: Command not found:", strconv.Quote(commandName))
			}
		}
	}
}

func (c *CLI) findCommand(commandName string) (command cmd.Command) {
	for i := 0; i < len(c.commands); i++ {
		if c.commands[i].GetName() == commandName {
			return c.commands[i]
		}
	}
	return nil
}

func (c *CLI) commandListFunction() func(string) []string {
	return func(s string) []string {
		var commands []string
		for i := 0; i < len(c.commands); i++ {
			commands = append(commands, c.commands[i].GetName())
		}
		return commands
	}
}

func banner() {
	fmt.Println(" _   _                           _   _         _")
	fmt.Println("| | | |                         | | | |       | |")
	fmt.Println("| |_| |  ___   _ __ ___    ___  | |_| | _   _ | |__")
	fmt.Println("|  _  | / _ \\ | '_ ` _ \\  / _ \\ |  _  || | | || '_ \\")
	fmt.Println("| | | || (_) || | | | | ||  __/ | | | || |_| || |_) |")
	fmt.Println("\\_| |_/ \\___/ |_| |_| |_| \\___| \\_| |_/ \\__,_||_.__/")
	fmt.Printf("\n=====================================================\n\n")
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/envman/envman"
	"github.com/codegangsta/cli"
)

const (
	defaultEnvStoreName string = ".envstore.yml"
)

var (
	stdinValue string
)

func isPipedData() bool {
	if stat, err := os.Stdin.Stat(); err != nil {
		return false
	} else if (stat.Mode() & os.ModeCharDevice) == 0 {
		return true
	}
	return false
}

func envStorePathInCurrentDir() (string, error) {
	return filepath.Abs(path.Join("./", defaultEnvStoreName))
}

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Befor parsing cli, and running command
	// we need to decide wich path will be used by envman
	envman.CurrentEnvStoreFilePath = c.String(PathKey)
	if envman.CurrentEnvStoreFilePath == "" {
		if path, err := envStorePathInCurrentDir(); err != nil {
			log.Fatal("[ENVMAN] - Failed to set envman work path in current dir:", err)
		} else {
			envman.CurrentEnvStoreFilePath = path
		}
	}

	envman.ToolMode = c.Bool(ToolKey)
	if envman.ToolMode {
		log.Info("[ENVMAN] - Tool mode on")
	}

	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run the Envman CLI.
func Run() {
	// Read piped data
	if isPipedData() {
		if bytes, err := ioutil.ReadAll(os.Stdin); err != nil {
			log.Error("[ENVMAN] - Failed to read stdin:", err)
		} else if len(bytes) > 0 {
			stdinValue = string(bytes)
		}
	}

	// Parse cl
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Environment variable manager"
	app.Version = "0.9.6"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Fatal("[ENVMAN] - Finished:", err)
	}
}
<commit_msg>start of v0.9.7<commit_after>package cli

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/envman/envman"
	"github.com/codegangsta/cli"
)

const (
	defaultEnvStoreName string = ".envstore.yml"
)

var (
	stdinValue string
)

func isPipedData() bool {
	if stat, err := os.Stdin.Stat(); err != nil {
		return false
	} else if (stat.Mode() & os.ModeCharDevice) == 0 {
		return true
	}
	return false
}

func envStorePathInCurrentDir() (string, error) {
	return filepath.Abs(path.Join("./", defaultEnvStoreName))
}

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Befor parsing cli, and running command
	// we need to decide wich path will be used by envman
	envman.CurrentEnvStoreFilePath = c.String(PathKey)
	if envman.CurrentEnvStoreFilePath == "" {
		if path, err := envStorePathInCurrentDir(); err != nil {
			log.Fatal("[ENVMAN] - Failed to set envman work path in current dir:", err)
		} else {
			envman.CurrentEnvStoreFilePath = path
		}
	}

	envman.ToolMode = c.Bool(ToolKey)
	if envman.ToolMode {
		log.Info("[ENVMAN] - Tool mode on")
	}

	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run the Envman CLI.
func Run() {
	// Read piped data
	if isPipedData() {
		if bytes, err := ioutil.ReadAll(os.Stdin); err != nil {
			log.Error("[ENVMAN] - Failed to read stdin:", err)
		} else if len(bytes) > 0 {
			stdinValue = string(bytes)
		}
	}

	// Parse cl
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Environment variable manager"
	app.Version = "0.9.7"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Fatal("[ENVMAN] - Finished:", err)
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func parseDebug(c *cli.Context) bool {
	if c.IsSet(DebugKey) {
		return c.Bool(DebugKey)
	}
	return false
}

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Setup
	err := stepman.CreateStepManDirIfNeeded()
	if err != nil {
		return err
	}

	// Debug mode
	stepman.DebugMode = parseDebug(c)
	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run ...
func Run() {
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Step manager"
	app.Version = "0.9.3"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Error("[STEPMAN] - Stepman finished:", err)
	}
}
<commit_msg>start of v0.9.4<commit_after>package cli

import (
	"fmt"
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func parseDebug(c *cli.Context) bool {
	if c.IsSet(DebugKey) {
		return c.Bool(DebugKey)
	}
	return false
}

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Setup
	err := stepman.CreateStepManDirIfNeeded()
	if err != nil {
		return err
	}

	// Debug mode
	stepman.DebugMode = parseDebug(c)
	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run ...
func Run() {
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Step manager"
	app.Version = "0.9.4"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Error("[STEPMAN] - Stepman finished:", err)
	}
}
<|endoftext|>


<commit_before>// Package cli provides all methods to control command line functions
package cli

import (
	"encoding/json"
	"fmt"
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

// Readline structure
type Readline struct {
	instance  *readline.Instance
	completer *readline.PrefixCompleter
	prompt    string
	next      chan struct{}
}

// Init set readline imain items
func Init(prompt, version string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("trace"),
			readline.PcItem("bgp"),
			readline.PcItem("connect"),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("lg"),
			readline.PcItem("ns"),
			readline.PcItem("dig"),
			readline.PcItem("whois"),
			readline.PcItem("scan"),
			readline.PcItem("peering"),
			readline.PcItem("help"),
			readline.PcItem("exit"),
		)
	)
	r.completer = completer
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println(version) // print banner
	checkUpdate(version)    // check update version
	r.prompt = prompt       // init local prompt
	return &r
}

// RemoveItemCompleter removes subitem(s) from a specific main item
func (r *Readline) RemoveItemCompleter(pcItem string) {
	child := []readline.PrefixCompleterInterface{}
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) != pcItem {
			child = append(child, p)
		}
	}

	r.completer.Children = child

}

// AddCompleter updates subitem(s) from a specific main item
func (r *Readline) AddCompleter(pcItem string, pcSubItems []string) {
	var pc readline.PrefixCompleter
	c := []readline.PrefixCompleterInterface{}
	for _, item := range pcSubItems {
		c = append(c, readline.PcItem(item))
	}
	pc.Name = []rune(pcItem + " ")
	pc.Children = c
	r.completer.Children = append(r.completer.Children, &pc)
}

// UpdateCompleter updates subitem(s) from a specific main item
func (r *Readline) UpdateCompleter(pcItem string, pcSubItems []string) {
	child := []readline.PrefixCompleterInterface{}
	var pc readline.PrefixCompleter
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) == pcItem {
			c := []readline.PrefixCompleterInterface{}
			for _, item := range pcSubItems {
				c = append(c, readline.PcItem(item))
			}
			pc.Name = []rune(pcItem + " ")
			pc.Children = c
			child = append(child, &pc)
		} else {
			child = append(child, p)
		}
	}
	if len(pc.Name) < 1 {
		// todo adding new
	}
	r.completer.Children = child
}

// SetPrompt set readline prompt and store it
func (r *Readline) SetPrompt(p string) {
	p = strings.ToLower(p)
	r.prompt = p
	r.instance.SetPrompt(p + "> ")
}

// UpdatePromptN appends readline prompt
func (r *Readline) UpdatePromptN(p string, n int) {
	var parts []string
	p = strings.ToLower(p)
	parts = strings.SplitAfterN(r.prompt, "/", n)
	if n <= len(parts) && n > -1 {
		parts[n-1] = p
		r.prompt = strings.Join(parts, "")
	} else {
		r.prompt += "/" + p
	}
	r.instance.SetPrompt(r.prompt + "> ")
}

// GetPrompt returns the current prompt string
func (r *Readline) GetPrompt() string {
	return r.prompt
}

// Refresh prompt
func (r *Readline) Refresh() {
	r.instance.Refresh()
}

// SetVim set mode to vim
func (r *Readline) SetVim() {
	if !r.instance.IsVimMode() {
		r.instance.SetVimMode(true)
		println("mode changed to vim")
	} else {
		println("mode already is vim")
	}
}

// SetEmacs set mode to emacs
func (r *Readline) SetEmacs() {
	if r.instance.IsVimMode() {
		r.instance.SetVimMode(false)
		println("mode changed to emacs")
	} else {
		println("mode already is emacs")
	}
}

// Next trigers to read next line
func (r *Readline) Next() {
	r.next <- struct{}{}
}

// Run the main loop
func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	r.next = next
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			cmd <- line
			if _, ok := <-next; !ok {
				break
			}
		}
	}()
}

// Close the readline instance
func (r *Readline) Close(next chan struct{}) {
	r.instance.Close()
}

// Help print out the main help
func (r *Readline) Help() {
	fmt.Println(`Usage:
	The myLG tool developed to troubleshoot networking situations.
	The vi/emacs mode,almost all basic features is supported. press tab to see what options are available.

	connect <provider name>     connects to external looking glass, press tab to see the menu
	node <city/country name>    connects to specific node at current looking glass, press tab to see the available nodes
	local                       back to local
	lg                          change mode to extenal looking glass
	ns                          change mode to name server looking up
	ping                        ping ip address or domain name
	dig                         name server looking up
	whois                       resolve AS number/IP/CIDR to holder (provides by ripe ncc)
	scan                        scan tcp ports (you can provide range >scan host minport maxport)
	peering                     peering information (provides by peeringdb.com)
	`)
}

// checkUpdate checks if any new version is available
func checkUpdate(version string) {
	type mylg struct {
		Version string
	}
	var appCtl mylg

	if version == "test" {
		return
	}

	resp, err := http.Get("http://mylg.io/appctl/mylg")
	if err != nil {
		println("error: check update has been failed ")
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		println("error: check update has been failed (2)" + err.Error())
		return
	}
	err = json.Unmarshal(body, &appCtl)
	if err != nil {
		println(err.Error())
		return
	}
	if version != appCtl.Version {
		fmt.Printf("New version is available (v%s) mylg.io/download\n", appCtl.Version)
	}
}

//Flag parses the command arguments syntax:
// -flag=x
// -flag x
// help
func Flag(args string) (string, map[string]interface{}) {
	var (
		r   = make(map[string]interface{}, 10)
		err error
	)
	args = strings.TrimSpace(args)
	re := regexp.MustCompile(`(?i)-([a-z]+)={0,1}\s{0,1}([0-9|a-z]+)`)
	f := re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		if len(kv) > 1 {
			r[kv[1]], err = strconv.Atoi(kv[2])
			if err != nil {
				r[kv[1]] = kv[2]
			}
			args = strings.Replace(args, kv[0], "", -1)
		}
	}
	if m, _ := regexp.MatchString(`(?i)help$`, args); m {
		r["help"] = true
	}
	args = strings.TrimSpace(args)
	return args, r
}

// SetFlag returns command option(s)
func SetFlag(flag map[string]interface{}, option string, v interface{}) interface{} {
	if sValue, ok := flag[option]; ok {
		switch v.(type) {
		case int:
			return sValue.(int)
		default:
			return sValue.(string)
		}
	} else {
		return v
	}
}
<commit_msg>optimized regex flag<commit_after>// Package cli provides all methods to control command line functions
package cli

import (
	"encoding/json"
	"fmt"
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

// Readline structure
type Readline struct {
	instance  *readline.Instance
	completer *readline.PrefixCompleter
	prompt    string
	next      chan struct{}
}

// Init set readline imain items
func Init(prompt, version string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("trace"),
			readline.PcItem("bgp"),
			readline.PcItem("connect"),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("lg"),
			readline.PcItem("ns"),
			readline.PcItem("dig"),
			readline.PcItem("whois"),
			readline.PcItem("scan"),
			readline.PcItem("peering"),
			readline.PcItem("help"),
			readline.PcItem("exit"),
		)
	)
	r.completer = completer
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println(version) // print banner
	checkUpdate(version)    // check update version
	r.prompt = prompt       // init local prompt
	return &r
}

// RemoveItemCompleter removes subitem(s) from a specific main item
func (r *Readline) RemoveItemCompleter(pcItem string) {
	child := []readline.PrefixCompleterInterface{}
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) != pcItem {
			child = append(child, p)
		}
	}

	r.completer.Children = child

}

// AddCompleter updates subitem(s) from a specific main item
func (r *Readline) AddCompleter(pcItem string, pcSubItems []string) {
	var pc readline.PrefixCompleter
	c := []readline.PrefixCompleterInterface{}
	for _, item := range pcSubItems {
		c = append(c, readline.PcItem(item))
	}
	pc.Name = []rune(pcItem + " ")
	pc.Children = c
	r.completer.Children = append(r.completer.Children, &pc)
}

// UpdateCompleter updates subitem(s) from a specific main item
func (r *Readline) UpdateCompleter(pcItem string, pcSubItems []string) {
	child := []readline.PrefixCompleterInterface{}
	var pc readline.PrefixCompleter
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) == pcItem {
			c := []readline.PrefixCompleterInterface{}
			for _, item := range pcSubItems {
				c = append(c, readline.PcItem(item))
			}
			pc.Name = []rune(pcItem + " ")
			pc.Children = c
			child = append(child, &pc)
		} else {
			child = append(child, p)
		}
	}
	if len(pc.Name) < 1 {
		// todo adding new
	}
	r.completer.Children = child
}

// SetPrompt set readline prompt and store it
func (r *Readline) SetPrompt(p string) {
	p = strings.ToLower(p)
	r.prompt = p
	r.instance.SetPrompt(p + "> ")
}

// UpdatePromptN appends readline prompt
func (r *Readline) UpdatePromptN(p string, n int) {
	var parts []string
	p = strings.ToLower(p)
	parts = strings.SplitAfterN(r.prompt, "/", n)
	if n <= len(parts) && n > -1 {
		parts[n-1] = p
		r.prompt = strings.Join(parts, "")
	} else {
		r.prompt += "/" + p
	}
	r.instance.SetPrompt(r.prompt + "> ")
}

// GetPrompt returns the current prompt string
func (r *Readline) GetPrompt() string {
	return r.prompt
}

// Refresh prompt
func (r *Readline) Refresh() {
	r.instance.Refresh()
}

// SetVim set mode to vim
func (r *Readline) SetVim() {
	if !r.instance.IsVimMode() {
		r.instance.SetVimMode(true)
		println("mode changed to vim")
	} else {
		println("mode already is vim")
	}
}

// SetEmacs set mode to emacs
func (r *Readline) SetEmacs() {
	if r.instance.IsVimMode() {
		r.instance.SetVimMode(false)
		println("mode changed to emacs")
	} else {
		println("mode already is emacs")
	}
}

// Next trigers to read next line
func (r *Readline) Next() {
	r.next <- struct{}{}
}

// Run the main loop
func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	r.next = next
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			cmd <- line
			if _, ok := <-next; !ok {
				break
			}
		}
	}()
}

// Close the readline instance
func (r *Readline) Close(next chan struct{}) {
	r.instance.Close()
}

// Help print out the main help
func (r *Readline) Help() {
	fmt.Println(`Usage:
	The myLG tool developed to troubleshoot networking situations.
	The vi/emacs mode,almost all basic features is supported. press tab to see what options are available.

	connect <provider name>     connects to external looking glass, press tab to see the menu
	node <city/country name>    connects to specific node at current looking glass, press tab to see the available nodes
	local                       back to local
	lg                          change mode to extenal looking glass
	ns                          change mode to name server looking up
	ping                        ping ip address or domain name
	dig                         name server looking up
	whois                       resolve AS number/IP/CIDR to holder (provides by ripe ncc)
	scan                        scan tcp ports (you can provide range >scan host minport maxport)
	peering                     peering information (provides by peeringdb.com)
	`)
}

// checkUpdate checks if any new version is available
func checkUpdate(version string) {
	type mylg struct {
		Version string
	}
	var appCtl mylg

	if version == "test" {
		return
	}

	resp, err := http.Get("http://mylg.io/appctl/mylg")
	if err != nil {
		println("error: check update has been failed ")
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		println("error: check update has been failed (2)" + err.Error())
		return
	}
	err = json.Unmarshal(body, &appCtl)
	if err != nil {
		println(err.Error())
		return
	}
	if version != appCtl.Version {
		fmt.Printf("New version is available (v%s) mylg.io/download\n", appCtl.Version)
	}
}

//Flag parses the command arguments syntax:
// -flag=x
// -flag x
// help
func Flag(args string) (string, map[string]interface{}) {
	var (
		r   = make(map[string]interface{}, 10)
		err error
	)
	args = strings.TrimSpace(args)
	re := regexp.MustCompile(`(?i)-([a-z]+)={0,1}\s{0,1}([0-9|a-z|-]+)`)
	f := re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		if len(kv) > 1 {
			r[kv[1]], err = strconv.Atoi(kv[2])
			if err != nil {
				r[kv[1]] = kv[2]
			}
			args = strings.Replace(args, kv[0], "", -1)
		}
	}
	if m, _ := regexp.MatchString(`(?i)help$`, args); m {
		r["help"] = true
	}
	args = strings.TrimSpace(args)
	return args, r
}

// SetFlag returns command option(s)
func SetFlag(flag map[string]interface{}, option string, v interface{}) interface{} {
	if sValue, ok := flag[option]; ok {
		switch v.(type) {
		case int:
			return sValue.(int)
		default:
			return sValue.(string)
		}
	} else {
		return v
	}
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "os/user"
  "strings"
  "regexp"
  "github.com/atotto/clipboard"
  "time"
)

func clip_str_to_path_line(clip_str string) string {
  if(strings.Count(clip_str, "\n") > 1) {
    return ""
  }
  usr, _ := user.Current()
  clip_str = strings.Replace(clip_str, "~", usr.HomeDir, 1)
                         //               file extension
                         //      path            |
                         //       |              |
  re := regexp.MustCompile(`[^\w](/[^@^:^\\^\(]+\.[a-z]{2,3})[^:]{0,9}(line.*?|:)([0-9]+)`)
  match := re.FindStringSubmatch(clip_str)
  if(len(match) > 1) {
    return strings.Join([]string{match[1], match[3]}, ":")
  }
  return ""
}

func main() {
  clip_str := nil
  while(True) {
    break
  }
  line := clip_str_to_path_line("this is /foo.py:30")
  if(line != "") {
    fmt.Println("line:", line)
  }

  clip_str := nil
  for {
    prev_value := clip_str
    clip_str, err := clipboard.ReadAll()
    if prev_value == nil {
      prev_value = clip_str
    }
    if clip_str != prev_value {
      fmt.Println("new value:", clip_str)
      path_line = clip_str_to_path_line(clip_str)
      if path_line {
        fmt.Println("got path_line:", path_line)
        exec.Run("/usr/local/bin/atom", path_line)
      }
    }
    time.Sleep(500 * time.Millisecond)
  }
}
<commit_msg>fuck go<commit_after><|endoftext|>


<commit_before>// Copyright Microsoft Corp.
// All rights reserved.

package network

import (
	"fmt"
	"net/http"
	"sync"

	"github.com/Azure/Aqua/core"
	"github.com/Azure/Aqua/log"
)

// Libnetwork network plugin name
const pluginName = "aqua"

// Libnetwork network plugin endpoint name
const endpointName = "NetworkDriver"

// NetPlugin object and its interface
type netPlugin struct {
	name     string
	version  string
	scope    string
	listener *core.Listener
	networks map[string]*azureNetwork
	sync.Mutex
}

type NetPlugin interface {
	Start(chan error) error
	Stop()

	GetListener() *core.Listener
}

// Creates a new NetPlugin object.
func NewPlugin(name string, version string) (NetPlugin, error) {
	return &netPlugin{
		name:    name,
		version: version,
		scope:   "local",
	}, nil
}

// Starts the plugin.
func (plugin *netPlugin) Start(errChan chan error) error {
	var socketName string
	if plugin.name != "test" {
		socketName = plugin.name
	}

	// Create the listener.
	listener, err := core.NewListener(socketName)
	if err != nil {
		log.Printf("Failed to create listener %v", err)
		return err
	}

	// Add protocol handlers.
	listener.AddHandler("Plugin", "Activate", plugin.activatePlugin)
	listener.AddHandler(endpointName, "GetCapabilities", plugin.getCapabilities)
	listener.AddHandler(endpointName, "CreateNetwork", plugin.createNetwork)
	listener.AddHandler(endpointName, "DeleteNetwork", plugin.deleteNetwork)
	listener.AddHandler(endpointName, "CreateEndpoint", plugin.createEndpoint)
	listener.AddHandler(endpointName, "DeleteEndpoint", plugin.deleteEndpoint)
	listener.AddHandler(endpointName, "Join", plugin.join)
	listener.AddHandler(endpointName, "Leave", plugin.leave)
	listener.AddHandler(endpointName, "EndpointOperInfo", plugin.endpointOperInfo)

	plugin.listener = listener

	err = listener.Start(errChan)
	if err != nil {
		log.Printf("Failed to start listener %v", err)
		return err
	}

	log.Printf("%s: Plugin started.", plugin.name)

	return nil
}

// Stops the plugin.
func (plugin *netPlugin) Stop() {
	plugin.listener.Stop()
	core.FreeSlaves()
	log.Printf("%s: Plugin stopped.\n", plugin.name)
}

// Returns the listener for the plugin.
func (plugin *netPlugin) GetListener() *core.Listener {
	return plugin.listener
}

func (plugin *netPlugin) networkExists(networkID string) bool {
	if plugin.networks[networkID] != nil {
		return true
	}
	return false
}

func (plugin *netPlugin) endpointExists(networkID string, endpointID string) bool {
	network := plugin.networks[networkID]
	if network == nil {
		return false
	}

	if network.endpoints[endpointID] == nil {
		return false
	}

	return true
}

type activateResponse struct {
	Implements []string
}

func (plugin *netPlugin) activatePlugin(w http.ResponseWriter, r *http.Request) {
	log.Request(plugin.name, "Activate", nil, nil)

	resp := &activateResponse{[]string{endpointName}}
	err := plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Activate", resp, err)
}

func (plugin *netPlugin) getCapabilities(w http.ResponseWriter, r *http.Request) {
	log.Request(plugin.name, "GetCapabilities", nil, nil)

	resp := map[string]string{"Scope": plugin.scope}
	err := plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "GetCapabilities", resp, err)
}

// All request and response formats are well known and are published by libnetwork
type createNetworkRequestFormat struct {
	NetworkID string
	Options   map[string]interface{}
}

func (plugin *netPlugin) createNetwork(w http.ResponseWriter, r *http.Request) {
	var req createNetworkRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "CreateNetwork", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	if plugin.networkExists(netID) {
		plugin.listener.SendError(w, "Network with same Id already exists")
		return
	}

	plugin.Lock()
	if plugin.networkExists(netID) {
		plugin.listener.SendError(w, "Network with same Id already exists")
		plugin.Unlock()
		return
	}

	if plugin.networks == nil {
		plugin.networks = make(map[string]*azureNetwork)
	}

	plugin.networks[netID] = &azureNetwork{networkId: netID}
	plugin.Unlock()

	// Empty response indicates success.
	resp := map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "CreateNetwork", resp, err)
}

type networkDeleteRequestFormat struct {
	NetworkID string
}

func (plugin *netPlugin) deleteNetwork(w http.ResponseWriter, r *http.Request) {
	var req networkDeleteRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "DeleteNetwork", req, err)

	if err != nil {
		return
	}

	if plugin.networkExists(req.NetworkID) {
		plugin.Lock()
		if plugin.networkExists(req.NetworkID) {
			delete(plugin.networks, req.NetworkID)
		}
		plugin.Unlock()
	}

	// Empty response indicates success.
	resp := map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "DeleteNetwork", resp, err)
}

type azInterface struct {
	Address     string
	AddressIPV6 string
	MacAddress  string
	ID          int
	SrcName     string
	DstPrefix   string
	GatewayIPv4 string
}

type createEndpointRequestFormat struct {
	NetworkID  string
	EndpointID string
	Options    map[string]interface{}
	Interface  *azInterface
}

type endpointResponse struct {
	Interface azInterface
}

func (plugin *netPlugin) createEndpoint(w http.ResponseWriter, r *http.Request) {
	var req createEndpointRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "CreateEndpoint", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	endID := req.EndpointID

	if !plugin.networkExists(netID) {
		plugin.listener.SendError(w, fmt.Sprintf("Could not find the network on which endpoint is requested: %s", netID))
		return
	}

	var interfaceToAttach string
	interfaceToAttach = ""
	var ipaddressToAttach string

	for key, value := range req.Options {

		if key == "eth" {
			interfaceToAttach = value.(string)
			log.Printf("Received request to attach following interface: %s", value)
		}

		if key == "com.docker.network.endpoint.ipaddresstoattach" {
			ipaddressToAttach = value.(string)
			log.Printf("Received request to attach following ipaddress: %s", value)
		}
	}

	// Now with ipam driver, docker will provide an interface
	// The values in that interface can be empty (in case of null ipam driver)
	// or they can contain some pre filled values (if ipam allocates ip addresses)
	if req.Interface != nil {
		ipaddressToAttach := req.Interface.Address
		log.Printf(
			"Interface found in endpoint creation request: "+
				"Addr:%s, ID:%v, Ipv6:%s, DstPrefix:%s, GatewayIpv4:%s, MacAddress:%s, SrcName:%s",
			ipaddressToAttach, req.Interface.ID,
			req.Interface.AddressIPV6,
			req.Interface.DstPrefix, req.Interface.GatewayIPv4,
			req.Interface.MacAddress, req.Interface.SrcName)
		//plugin.listener.SendError(w, errMessage)
		//return
	}

	log.Printf("Trying to create an endpoint\n\tn/w-id:%s \n\tep-id:%s\n", string(netID), string(endID))

	// lets lock driver for now.. will optimize later
	plugin.Lock()
	if !plugin.networkExists(netID) {
		plugin.listener.SendError(w, fmt.Sprintf("Could not find [networkID:%s]\n", netID))
		return
	}
	if plugin.endpointExists(netID, endID) {
		plugin.listener.SendError(w, fmt.Sprintf("Endpoint already exists [networkID:%s endpointID:%s]\n", netID, endID))
		return
	}

	log.Printf("Endpoint created successfully "+
		"\n\tn/w-id:%s \n\tep-id:%s\n", string(netID), string(endID))

	rAddress,
		rAddressIPV6,
		rMacAddress,
		rID,
		rSrcName,
		rDstPrefix,
		rGatewayIPv4, ermsg := core.GetTargetInterface(interfaceToAttach, ipaddressToAttach)

	if ermsg != "" {
		plugin.listener.SendError(w, ermsg)
		plugin.Unlock()
		return
	}

	targetInterface := azureInterface{
		Address:     rAddress,
		AddressIPV6: rAddressIPV6,
		MacAddress:  rMacAddress,
		ID:          rID,
		SrcName:     rSrcName,
		DstPrefix:   rDstPrefix,
		GatewayIPv4: rGatewayIPv4,
	}
	network := plugin.networks[netID]
	if network.endpoints == nil {
		network.endpoints = make(map[string]*azureEndpoint)
	}
	network.endpoints[endID] = &azureEndpoint{endpointID: endID, networkID: netID}
	network.endpoints[endID].azureInterface = targetInterface

	plugin.Unlock()

	/*defer func() {
	if err != nil {
	n.Lock()
	delete(n.endpoints, eid)
	n.Unlock()
	}
	}()*/

	/********END**********/

	respIface := &azInterface{
		Address:     targetInterface.Address.String(),
		MacAddress:  targetInterface.MacAddress.String(),
		GatewayIPv4: targetInterface.GatewayIPv4.String(),
	}
	resp := &endpointResponse{
		Interface: *respIface,
	}

	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "CreateEndpoint", resp, err)
}

type joinRequestFormat struct {
	NetworkID  string
	EndpointID string
	SandboxKey string
	Options    map[string]interface{}
}

type interfaceToJoin struct {
	SrcName   string
	DstPrefix string
}

type joinResponseFormat struct {
	InterfaceName interfaceToJoin
	Gateway       string
	GatewayIPv6   string
	StaticRoutes  []*staticRoute
}

type staticRoute struct {
	Destination string
	RouteType   int
	NextHop     string
}

func (plugin *netPlugin) join(w http.ResponseWriter, r *http.Request) {
	var req joinRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "Join", req, err)

	if err != nil {
		return
	}

	endID := req.EndpointID
	netID := req.NetworkID
	sandboxKey := req.SandboxKey
	fmt.Println("Received a request to join endpoint: ", endID, " network: ", netID)

	if !plugin.endpointExists(netID, endID) {
		plugin.listener.SendError(w, "cannot find endpoint for which join is requested")
		return
	}

	endpoint := plugin.networks[netID].endpoints[endID]

	ifname := &interfaceToJoin{
		SrcName:   endpoint.azureInterface.SrcName,
		DstPrefix: endpoint.azureInterface.DstPrefix,
	}

	resp := &joinResponseFormat{
		InterfaceName: *ifname,
		Gateway:       endpoint.azureInterface.GatewayIPv4.String(),
	}

	plugin.Lock()
	endpoint.sandboxKey = sandboxKey
	plugin.Unlock()

	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Join", resp, err)

	fmt.Printf("srcname: %s dstPRefix:%s \n", ifname.SrcName, ifname.DstPrefix)

	fmt.Printf("Joined endpoint\n Network: %s\n Endpoint: %s\n Sandbox: %s\n",
		req.NetworkID, req.EndpointID, req.SandboxKey)
}

type endpointDeleteRequestFormat struct {
	NetworkID  string
	EndpointID string
}

func (plugin *netPlugin) deleteEndpoint(w http.ResponseWriter, r *http.Request) {
	var req endpointDeleteRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "DeleteEndpoint", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	endID := req.EndpointID

	plugin.Lock()
	defer plugin.Unlock()
	if !plugin.endpointExists(netID, endID) {
		// idempotent or throw error?
		fmt.Println("Endpoint not found network: ", netID, " endpointID: ", endID)
	} else {
		network := plugin.networks[netID]
		ep := network.endpoints[endID]
		iface := ep.azureInterface
		err = core.CleanupAfterContainerDeletion(iface.SrcName, iface.MacAddress)
		if err != nil {
			log.Printf("%s: DeleteEndpoint cleanup failure %s", plugin.name, err.Error())
		}
		delete(network.endpoints, endID)
	}

	// Empty response indicates success.
	resp := &map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "DeleteEndpoint", resp, err)
}

type leaveRequestFormat struct {
	NetworkID  string
	EndpointID string
}

type leaveResponse struct {
}

func (plugin *netPlugin) leave(w http.ResponseWriter, r *http.Request) {
	var req leaveRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "Leave", req, err)

	if err != nil {
		return
	}

	// Empty response indicates success.
	resp := &leaveResponse{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Leave", resp, err)
}

type endpointOperInfoRequestFormat struct {
	NetworkID  string
	EndpointID string
}

type endpointOperInfoResponseFormat struct {
	Value map[string]interface{}
}

func (plugin *netPlugin) endpointOperInfo(w http.ResponseWriter, r *http.Request) {
	var req endpointOperInfoRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "EndpointOperInfo", req, err)

	if err != nil {
		return
	}

	value := make(map[string]interface{})
	//value["com.docker.network.endpoint.macaddress"] = macAddress
	//value["MacAddress"] = macAddress

	resp := &endpointOperInfoResponseFormat{Value: value}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "EndpointOperInfo", resp, err)
}
<commit_msg>Minor renaming for consistency with libnetwork terminology<commit_after>// Copyright Microsoft Corp.
// All rights reserved.

package network

import (
	"fmt"
	"net/http"
	"sync"

	"github.com/Azure/Aqua/core"
	"github.com/Azure/Aqua/log"
)

// Libnetwork network plugin endpoint type
const endpointType = "NetworkDriver"

// NetPlugin object and its interface
type netPlugin struct {
	name     string
	version  string
	scope    string
	listener *core.Listener
	networks map[string]*azureNetwork
	sync.Mutex
}

type NetPlugin interface {
	Start(chan error) error
	Stop()
	GetListener() *core.Listener
}

// Creates a new NetPlugin object.
func NewPlugin(name string, version string) (NetPlugin, error) {
	return &netPlugin{
		name:    name,
		version: version,
		scope:   "local",
	}, nil
}

// Starts the plugin.
func (plugin *netPlugin) Start(errChan chan error) error {
	var socketName string
	if plugin.name != "test" {
		socketName = plugin.name
	}

	// Create the listener.
	listener, err := core.NewListener(socketName)
	if err != nil {
		log.Printf("Failed to create listener %v", err)
		return err
	}

	// Add protocol handlers.
	listener.AddHandler("Plugin", "Activate", plugin.activatePlugin)
	listener.AddHandler(endpointType, "GetCapabilities", plugin.getCapabilities)
	listener.AddHandler(endpointType, "CreateNetwork", plugin.createNetwork)
	listener.AddHandler(endpointType, "DeleteNetwork", plugin.deleteNetwork)
	listener.AddHandler(endpointType, "CreateEndpoint", plugin.createEndpoint)
	listener.AddHandler(endpointType, "DeleteEndpoint", plugin.deleteEndpoint)
	listener.AddHandler(endpointType, "Join", plugin.join)
	listener.AddHandler(endpointType, "Leave", plugin.leave)
	listener.AddHandler(endpointType, "EndpointOperInfo", plugin.endpointOperInfo)

	plugin.listener = listener

	err = listener.Start(errChan)
	if err != nil {
		log.Printf("Failed to start listener %v", err)
		return err
	}

	log.Printf("%s: Plugin started.", plugin.name)

	return nil
}

// Stops the plugin.
func (plugin *netPlugin) Stop() {
	plugin.listener.Stop()
	core.FreeSlaves()
	log.Printf("%s: Plugin stopped.\n", plugin.name)
}

// Returns the listener for the plugin.
func (plugin *netPlugin) GetListener() *core.Listener {
	return plugin.listener
}

func (plugin *netPlugin) networkExists(networkID string) bool {
	if plugin.networks[networkID] != nil {
		return true
	}
	return false
}

func (plugin *netPlugin) endpointExists(networkID string, endpointID string) bool {
	network := plugin.networks[networkID]
	if network == nil {
		return false
	}

	if network.endpoints[endpointID] == nil {
		return false
	}

	return true
}

type activateResponse struct {
	Implements []string
}

func (plugin *netPlugin) activatePlugin(w http.ResponseWriter, r *http.Request) {
	log.Request(plugin.name, "Activate", nil, nil)

	resp := &activateResponse{[]string{endpointType}}
	err := plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Activate", resp, err)
}

func (plugin *netPlugin) getCapabilities(w http.ResponseWriter, r *http.Request) {
	log.Request(plugin.name, "GetCapabilities", nil, nil)

	resp := map[string]string{"Scope": plugin.scope}
	err := plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "GetCapabilities", resp, err)
}

// All request and response formats are well known and are published by libnetwork
type createNetworkRequestFormat struct {
	NetworkID string
	Options   map[string]interface{}
}

func (plugin *netPlugin) createNetwork(w http.ResponseWriter, r *http.Request) {
	var req createNetworkRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "CreateNetwork", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	if plugin.networkExists(netID) {
		plugin.listener.SendError(w, "Network with same Id already exists")
		return
	}

	plugin.Lock()
	if plugin.networkExists(netID) {
		plugin.listener.SendError(w, "Network with same Id already exists")
		plugin.Unlock()
		return
	}

	if plugin.networks == nil {
		plugin.networks = make(map[string]*azureNetwork)
	}

	plugin.networks[netID] = &azureNetwork{networkId: netID}
	plugin.Unlock()

	// Empty response indicates success.
	resp := map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "CreateNetwork", resp, err)
}

type networkDeleteRequestFormat struct {
	NetworkID string
}

func (plugin *netPlugin) deleteNetwork(w http.ResponseWriter, r *http.Request) {
	var req networkDeleteRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "DeleteNetwork", req, err)

	if err != nil {
		return
	}

	if plugin.networkExists(req.NetworkID) {
		plugin.Lock()
		if plugin.networkExists(req.NetworkID) {
			delete(plugin.networks, req.NetworkID)
		}
		plugin.Unlock()
	}

	// Empty response indicates success.
	resp := map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "DeleteNetwork", resp, err)
}

type azInterface struct {
	Address     string
	AddressIPV6 string
	MacAddress  string
	ID          int
	SrcName     string
	DstPrefix   string
	GatewayIPv4 string
}

type createEndpointRequestFormat struct {
	NetworkID  string
	EndpointID string
	Options    map[string]interface{}
	Interface  *azInterface
}

type endpointResponse struct {
	Interface azInterface
}

func (plugin *netPlugin) createEndpoint(w http.ResponseWriter, r *http.Request) {
	var req createEndpointRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "CreateEndpoint", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	endID := req.EndpointID

	if !plugin.networkExists(netID) {
		plugin.listener.SendError(w, fmt.Sprintf("Could not find the network on which endpoint is requested: %s", netID))
		return
	}

	var interfaceToAttach string
	interfaceToAttach = ""
	var ipaddressToAttach string

	for key, value := range req.Options {

		if key == "eth" {
			interfaceToAttach = value.(string)
			log.Printf("Received request to attach following interface: %s", value)
		}

		if key == "com.docker.network.endpoint.ipaddresstoattach" {
			ipaddressToAttach = value.(string)
			log.Printf("Received request to attach following ipaddress: %s", value)
		}
	}

	// Now with ipam driver, docker will provide an interface
	// The values in that interface can be empty (in case of null ipam driver)
	// or they can contain some pre filled values (if ipam allocates ip addresses)
	if req.Interface != nil {
		ipaddressToAttach := req.Interface.Address
		log.Printf(
			"Interface found in endpoint creation request: "+
				"Addr:%s, ID:%v, Ipv6:%s, DstPrefix:%s, GatewayIpv4:%s, MacAddress:%s, SrcName:%s",
			ipaddressToAttach, req.Interface.ID,
			req.Interface.AddressIPV6,
			req.Interface.DstPrefix, req.Interface.GatewayIPv4,
			req.Interface.MacAddress, req.Interface.SrcName)
		//plugin.listener.SendError(w, errMessage)
		//return
	}

	log.Printf("Trying to create an endpoint\n\tn/w-id:%s \n\tep-id:%s\n", string(netID), string(endID))

	// lets lock driver for now.. will optimize later
	plugin.Lock()
	if !plugin.networkExists(netID) {
		plugin.listener.SendError(w, fmt.Sprintf("Could not find [networkID:%s]\n", netID))
		return
	}
	if plugin.endpointExists(netID, endID) {
		plugin.listener.SendError(w, fmt.Sprintf("Endpoint already exists [networkID:%s endpointID:%s]\n", netID, endID))
		return
	}

	log.Printf("Endpoint created successfully "+
		"\n\tn/w-id:%s \n\tep-id:%s\n", string(netID), string(endID))

	rAddress,
		rAddressIPV6,
		rMacAddress,
		rID,
		rSrcName,
		rDstPrefix,
		rGatewayIPv4, ermsg := core.GetTargetInterface(interfaceToAttach, ipaddressToAttach)

	if ermsg != "" {
		plugin.listener.SendError(w, ermsg)
		plugin.Unlock()
		return
	}

	targetInterface := azureInterface{
		Address:     rAddress,
		AddressIPV6: rAddressIPV6,
		MacAddress:  rMacAddress,
		ID:          rID,
		SrcName:     rSrcName,
		DstPrefix:   rDstPrefix,
		GatewayIPv4: rGatewayIPv4,
	}
	network := plugin.networks[netID]
	if network.endpoints == nil {
		network.endpoints = make(map[string]*azureEndpoint)
	}
	network.endpoints[endID] = &azureEndpoint{endpointID: endID, networkID: netID}
	network.endpoints[endID].azureInterface = targetInterface

	plugin.Unlock()

	/*defer func() {
	if err != nil {
	n.Lock()
	delete(n.endpoints, eid)
	n.Unlock()
	}
	}()*/

	/********END**********/

	respIface := &azInterface{
		Address:     targetInterface.Address.String(),
		MacAddress:  targetInterface.MacAddress.String(),
		GatewayIPv4: targetInterface.GatewayIPv4.String(),
	}
	resp := &endpointResponse{
		Interface: *respIface,
	}

	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "CreateEndpoint", resp, err)
}

type joinRequestFormat struct {
	NetworkID  string
	EndpointID string
	SandboxKey string
	Options    map[string]interface{}
}

type interfaceToJoin struct {
	SrcName   string
	DstPrefix string
}

type joinResponseFormat struct {
	InterfaceName interfaceToJoin
	Gateway       string
	GatewayIPv6   string
	StaticRoutes  []*staticRoute
}

type staticRoute struct {
	Destination string
	RouteType   int
	NextHop     string
}

func (plugin *netPlugin) join(w http.ResponseWriter, r *http.Request) {
	var req joinRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "Join", req, err)

	if err != nil {
		return
	}

	endID := req.EndpointID
	netID := req.NetworkID
	sandboxKey := req.SandboxKey
	fmt.Println("Received a request to join endpoint: ", endID, " network: ", netID)

	if !plugin.endpointExists(netID, endID) {
		plugin.listener.SendError(w, "cannot find endpoint for which join is requested")
		return
	}

	endpoint := plugin.networks[netID].endpoints[endID]

	ifname := &interfaceToJoin{
		SrcName:   endpoint.azureInterface.SrcName,
		DstPrefix: endpoint.azureInterface.DstPrefix,
	}

	resp := &joinResponseFormat{
		InterfaceName: *ifname,
		Gateway:       endpoint.azureInterface.GatewayIPv4.String(),
	}

	plugin.Lock()
	endpoint.sandboxKey = sandboxKey
	plugin.Unlock()

	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Join", resp, err)

	fmt.Printf("srcname: %s dstPRefix:%s \n", ifname.SrcName, ifname.DstPrefix)

	fmt.Printf("Joined endpoint\n Network: %s\n Endpoint: %s\n Sandbox: %s\n",
		req.NetworkID, req.EndpointID, req.SandboxKey)
}

type endpointDeleteRequestFormat struct {
	NetworkID  string
	EndpointID string
}

func (plugin *netPlugin) deleteEndpoint(w http.ResponseWriter, r *http.Request) {
	var req endpointDeleteRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "DeleteEndpoint", req, err)

	if err != nil {
		return
	}

	netID := req.NetworkID
	endID := req.EndpointID

	plugin.Lock()
	defer plugin.Unlock()
	if !plugin.endpointExists(netID, endID) {
		// idempotent or throw error?
		fmt.Println("Endpoint not found network: ", netID, " endpointID: ", endID)
	} else {
		network := plugin.networks[netID]
		ep := network.endpoints[endID]
		iface := ep.azureInterface
		err = core.CleanupAfterContainerDeletion(iface.SrcName, iface.MacAddress)
		if err != nil {
			log.Printf("%s: DeleteEndpoint cleanup failure %s", plugin.name, err.Error())
		}
		delete(network.endpoints, endID)
	}

	// Empty response indicates success.
	resp := &map[string]string{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "DeleteEndpoint", resp, err)
}

type leaveRequestFormat struct {
	NetworkID  string
	EndpointID string
}

type leaveResponse struct {
}

func (plugin *netPlugin) leave(w http.ResponseWriter, r *http.Request) {
	var req leaveRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "Leave", req, err)

	if err != nil {
		return
	}

	// Empty response indicates success.
	resp := &leaveResponse{}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "Leave", resp, err)
}

type endpointOperInfoRequestFormat struct {
	NetworkID  string
	EndpointID string
}

type endpointOperInfoResponseFormat struct {
	Value map[string]interface{}
}

func (plugin *netPlugin) endpointOperInfo(w http.ResponseWriter, r *http.Request) {
	var req endpointOperInfoRequestFormat

	err := plugin.listener.Decode(w, r, &req)

	log.Request(plugin.name, "EndpointOperInfo", req, err)

	if err != nil {
		return
	}

	value := make(map[string]interface{})
	//value["com.docker.network.endpoint.macaddress"] = macAddress
	//value["MacAddress"] = macAddress

	resp := &endpointOperInfoResponseFormat{Value: value}
	err = plugin.listener.Encode(w, resp)

	log.Response(plugin.name, "EndpointOperInfo", resp, err)
}
<|endoftext|>


<commit_before>package gw2api

import (
	"net/url"
	"strconv"
)

// TeamAssoc Points/Kills/Deaths per team
type TeamAssoc struct {
	Green int `json:"green"`
	Blue  int `json:"blue"`
	Red   int `json:"red"`
}

// Bonus - Map bonuses and current owner indetified by Color/Neutral
type Bonus struct {
	Owner string `json:"owner"`
	Type  string `json:"type"`
}

// MatchObjective - Map objectives such as towers, keeps, etc
type MatchObjective struct {
	ID          string `json:"id"`
	Type        string `json:"type"`
	Owner       string `json:"owner"`
	LastFlipped string `json:"last_flipped"`
	ClaimedBy   string `json:"claimed_by"`
	ClaimedAt   string `json:"claimed_at"`
}

// MapWvW - One of the four maps and their status
type MapWvW struct {
	ID         int              `json:"id"`
	Type       string           `json:"type"`
	Scores     TeamAssoc        `json:"scores"`
	Bonuses    []Bonus          `json:"bonuses"`
	Deaths     TeamAssoc        `json:"deaths"`
	Kills      TeamAssoc        `json:"kills"`
	Objectives []MatchObjective `json:"objectives"`
}

// Match including overall stats and indivdual maps with stats
type Match struct {
	ID        string    `json:"id"`
	StartTime string    `json:"start_time"`
	EndTime   string    `json:"end_time"`
	Scores    TeamAssoc `json:"scores"`
	Worlds    TeamAssoc `json:"worlds"`
	Deaths    TeamAssoc `json:"deaths"`
	Kills     TeamAssoc `json:"kills"`
	Maps      []MapWvW  `json:"maps"`
}

// Matches returns a list of all current match ids in the form of %d-%d
func (gw2 *GW2Api) Matches() (res []string, err error) {
	ver := "v2"
	tag := "wvw/matches"
	err = gw2.fetchEndpoint(ver, tag, nil, &res)
	return
}

// MatchIds returns matches as requested by ids in the form
// provided by Matches(). Use special id `all` for every match in US/EU
func (gw2 *GW2Api) MatchIds(ids ...string) (match []Match, err error) {
	ver := "v2"
	tag := "wvw/matches"
	params := url.Values{}
	params.Add("ids", commaList(ids))
	err = gw2.fetchEndpoint(ver, tag, params, &match)
	return
}

// MatchWorld finds the match the server id is participating in
func (gw2 *GW2Api) MatchWorld(worldId int) (match Match, err error) {
	ver := "v2"
	tag := "wvw/matches"
	params := url.Values{}
	params.Add("world", strconv.Itoa(worldId))
	err = gw2.fetchEndpoint(ver, tag, params, &match)
	return
}

// Objective - Map objectives such as towers, keeps, etc
type Objective struct {
	ID       string    `json:"id"`
	Name     string    `json:"name"`
	SectorID int       `json:"sector_id"`
	Type     string    `json:"type"`
	MapType  string    `json:"map_type"`
	MapID    int       `json:"map_id"`
	Coord    []float32 `json:"coord"`
	Marker   string    `json:"marker"`
}

// Objectives returns a list of all objectives on wvw maps
func (gw2 *GW2Api) Objectives() (res []string, err error) {
	ver := "v2"
	tag := "wvw/objectives"
	err = gw2.fetchEndpoint(ver, tag, nil, &res)
	return
}

// ObjectiveIds returns a list of objectives as request by ids. Use special id
// `all` to request all objectives
func (gw2 *GW2Api) ObjectiveIds(lang string, ids ...string) (objs []Objective, err error) {
	ver := "v2"
	tag := "wvw/objectives"
	params := url.Values{}
	if lang != "" {
		params.Add("lang", lang)
	}
	params.Add("ids", commaList(ids))
	err = gw2.fetchEndpoint(ver, tag, params, &objs)
	return
}
<commit_msg>golint complains<commit_after>package gw2api

import (
	"net/url"
	"strconv"
)

// TeamAssoc Points/Kills/Deaths per team
type TeamAssoc struct {
	Green int `json:"green"`
	Blue  int `json:"blue"`
	Red   int `json:"red"`
}

// Bonus - Map bonuses and current owner indetified by Color/Neutral
type Bonus struct {
	Owner string `json:"owner"`
	Type  string `json:"type"`
}

// MatchObjective - Map objectives such as towers, keeps, etc
type MatchObjective struct {
	ID          string `json:"id"`
	Type        string `json:"type"`
	Owner       string `json:"owner"`
	LastFlipped string `json:"last_flipped"`
	ClaimedBy   string `json:"claimed_by"`
	ClaimedAt   string `json:"claimed_at"`
}

// MapWvW - One of the four maps and their status
type MapWvW struct {
	ID         int              `json:"id"`
	Type       string           `json:"type"`
	Scores     TeamAssoc        `json:"scores"`
	Bonuses    []Bonus          `json:"bonuses"`
	Deaths     TeamAssoc        `json:"deaths"`
	Kills      TeamAssoc        `json:"kills"`
	Objectives []MatchObjective `json:"objectives"`
}

// Match including overall stats and indivdual maps with stats
type Match struct {
	ID        string    `json:"id"`
	StartTime string    `json:"start_time"`
	EndTime   string    `json:"end_time"`
	Scores    TeamAssoc `json:"scores"`
	Worlds    TeamAssoc `json:"worlds"`
	Deaths    TeamAssoc `json:"deaths"`
	Kills     TeamAssoc `json:"kills"`
	Maps      []MapWvW  `json:"maps"`
}

// Matches returns a list of all current match ids in the form of %d-%d
func (gw2 *GW2Api) Matches() (res []string, err error) {
	ver := "v2"
	tag := "wvw/matches"
	err = gw2.fetchEndpoint(ver, tag, nil, &res)
	return
}

// MatchIds returns matches as requested by ids in the form
// provided by Matches(). Use special id `all` for every match in US/EU
func (gw2 *GW2Api) MatchIds(ids ...string) (match []Match, err error) {
	ver := "v2"
	tag := "wvw/matches"
	params := url.Values{}
	params.Add("ids", commaList(ids))
	err = gw2.fetchEndpoint(ver, tag, params, &match)
	return
}

// MatchWorld finds the match the server id is participating in
func (gw2 *GW2Api) MatchWorld(worldID int) (match Match, err error) {
	ver := "v2"
	tag := "wvw/matches"
	params := url.Values{}
	params.Add("world", strconv.Itoa(worldID))
	err = gw2.fetchEndpoint(ver, tag, params, &match)
	return
}

// Objective - Map objectives such as towers, keeps, etc
type Objective struct {
	ID       string    `json:"id"`
	Name     string    `json:"name"`
	SectorID int       `json:"sector_id"`
	Type     string    `json:"type"`
	MapType  string    `json:"map_type"`
	MapID    int       `json:"map_id"`
	Coord    []float32 `json:"coord"`
	Marker   string    `json:"marker"`
}

// Objectives returns a list of all objectives on wvw maps
func (gw2 *GW2Api) Objectives() (res []string, err error) {
	ver := "v2"
	tag := "wvw/objectives"
	err = gw2.fetchEndpoint(ver, tag, nil, &res)
	return
}

// ObjectiveIds returns a list of objectives as request by ids. Use special id
// `all` to request all objectives
func (gw2 *GW2Api) ObjectiveIds(lang string, ids ...string) (objs []Objective, err error) {
	ver := "v2"
	tag := "wvw/objectives"
	params := url.Values{}
	if lang != "" {
		params.Add("lang", lang)
	}
	params.Add("ids", commaList(ids))
	err = gw2.fetchEndpoint(ver, tag, params, &objs)
	return
}
<|endoftext|>


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

package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/jacksinn/tri/todo"
)

// addCmd represents the add command
var addCmd = &cobra.Command{
	Use:   "add",
	Short: "Add a new todo",
	Long: `Add will create a new todo item to the list`,
	Run: addRun,
}

func init() {
	RootCmd.AddCommand(addCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// addCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func addRun(cmd *cobra.Command, args []string){
	items := []todo.Item{}
	for _, x := range args {
		items = append(items, todo.Item{Text: x})
	}
	err := todo.SaveItems("/Users/steven/.tridos.json", items)
	if err != nil {
		fmt.Errorf("%v", err)
	}
	fmt.Printf("%#v\n", items)
}<commit_msg>Default<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/jacksinn/tri/todo"
)

// addCmd represents the add command
var addCmd = &cobra.Command{
	Use:   "add",
	Short: "Add a new todo",
	Long: `Add will create a new todo item to the list`,
	Run: addRun,
}

func init() {
	RootCmd.AddCommand(addCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// addCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func addRun(cmd *cobra.Command, args []string){
	items := []todo.Item{}
	for _, x := range args {
		items = append(items, todo.Item{Text: x})
	}
	err := todo.SaveItems("/Users/steven/.tridos.json", items)
	if err != nil {
		fmt.Errorf("%v", err)
	}
	//fmt.Printf("%#v\n", items)
}<|endoftext|>


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

package cmd

import (
	"fmt"
	"github.com/globocom/tsuru/fs"
	"io"
	"net/http"
	"os"
	"sort"
	"strings"
)

type exiter interface {
	Exit(int)
}

type osExiter struct{}

func (e osExiter) Exit(code int) {
	os.Exit(code)
}

type Manager struct {
	Commands      map[string]interface{}
	name          string
	stdout        io.Writer
	stderr        io.Writer
	stdin         io.Reader
	version       string
	versionHeader string
	e             exiter
	original      string
	wrong         bool
}

func NewManager(name, ver, verHeader string, stdout, stderr io.Writer, stdin io.Reader) *Manager {
	manager := &Manager{name: name, version: ver, versionHeader: verHeader, stdout: stdout, stderr: stderr, stdin: stdin}
	manager.Register(&help{manager})
	manager.Register(&version{manager})
	return manager
}

func BuildBaseManager(name, version, versionHeader string) *Manager {
	m := NewManager(name, version, versionHeader, os.Stdout, os.Stderr, os.Stdin)
	m.Register(&login{})
	m.Register(&logout{})
	m.Register(&userCreate{})
	m.Register(&userRemove{})
	m.Register(&teamCreate{})
	m.Register(&teamRemove{})
	m.Register(&teamList{})
	m.Register(&teamUserAdd{})
	m.Register(&teamUserRemove{})
	m.Register(&target{})
	return m
}

func (m *Manager) Register(command interface{}) {
	if m.Commands == nil {
		m.Commands = make(map[string]interface{})
	}
	name := command.(Infoer).Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
}

func (m *Manager) Run(args []string) {
	var status int
	if len(args) == 0 {
		args = append(args, "help")
	}
	name := args[0]
	command, ok := m.Commands[name]
	if !ok {
		fmt.Fprintf(m.stderr, "command %s does not exist\n", args[0])
		m.finisher().Exit(1)
		return
	}
	args = args[1:]
	if len(args) < command.(Infoer).Info().MinArgs && name != "help" {
		m.wrong = true
		m.original = command.(Infoer).Info().Name
		command = m.Commands["help"]
		args = []string{name}
		status = 1
	}
	context := Context{args, m.stdout, m.stderr, m.stdin}
	client := NewClient(&http.Client{}, &context, m.version, m.versionHeader)
	err := command.(Command).Run(&context, client)
	if err != nil {
		errorMsg := err.Error()
		if strings.HasPrefix(errorMsg, "Invalid token") {
			errorMsg = `You're not authenticated or your session has expired. Please use "login" command for authentication.`
		}
		if !strings.HasSuffix(errorMsg, "\n") {
			errorMsg += "\n"
		}
		io.WriteString(m.stderr, errorMsg)
		status = 1
	}
	m.finisher().Exit(status)
}

func (m *Manager) finisher() exiter {
	if m.e == nil {
		m.e = osExiter{}
	}
	return m.e
}

type Infoer interface {
	Info() *Info
}

type Command interface {
	Run(context *Context, client Doer) error
}

type Context struct {
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
	Stdin  io.Reader
}

type Info struct {
	Name    string
	MinArgs int
	Usage   string
	Desc    string
}

type help struct {
	manager *Manager
}

func (c *help) Info() *Info {
	return &Info{
		Name:  "help",
		Usage: "command [args]",
	}
}

func (c *help) Run(context *Context, client Doer) error {
	output := fmt.Sprintf("%s version %s.\n\n", c.manager.name, c.manager.version)
	if c.manager.wrong {
		output += fmt.Sprintf("ERROR: not enough arguments to call %s.\n\n", c.manager.original)
	}
	if len(context.Args) > 0 {
		cmd, ok := c.manager.Commands[context.Args[0]]
		if !ok {
			return fmt.Errorf("Command %s does not exist.", context.Args[0])
		}
		info := cmd.(Infoer).Info()
		output += fmt.Sprintf("Usage: %s %s\n", c.manager.name, info.Usage)
		output += fmt.Sprintf("\n%s\n", info.Desc)
		if info.MinArgs > 0 {
			output += fmt.Sprintf("\nMinimum arguments: %d\n", info.MinArgs)
		}
	} else {
		output += fmt.Sprintf("Usage: %s %s\n\nAvailable commands:\n", c.manager.name, c.Info().Usage)
		var commands []string
		for k := range c.manager.Commands {
			commands = append(commands, k)
		}
		sort.Strings(commands)
		for _, command := range commands {
			output += fmt.Sprintf("  %s\n", command)
		}
		output += fmt.Sprintf("\nRun %s help <commandname> to get more information about a specific command.\n", c.manager.name)
	}
	io.WriteString(context.Stdout, output)
	return nil
}

type version struct {
	manager *Manager
}

func (c *version) Info() *Info {
	return &Info{
		Name:    "version",
		MinArgs: 0,
		Usage:   "version",
		Desc:    "display the current version",
	}
}

func (c *version) Run(context *Context, client Doer) error {
	fmt.Fprintf(context.Stdout, "%s version %s.\n", c.manager.name, c.manager.version)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// validateVersion checks whether current version is greater or equal to
// supported version.
func validateVersion(supported, current string) bool {
	var (
		bigger bool
		limit  int
	)
	partsSupported := strings.Split(supported, ".")
	partsCurrent := strings.Split(current, ".")
	if len(partsSupported) > len(partsCurrent) {
		limit = len(partsCurrent)
		bigger = true
	} else {
		limit = len(partsSupported)
	}
	for i := 0; i < limit; i++ {
		if partsCurrent[i] < partsSupported[i] {
			return false
		}
	}
	if bigger {
		return false
	}
	return true
}
<commit_msg>cmd: improve error message when user is not authenticated<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"github.com/globocom/tsuru/fs"
	"io"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strings"
)

type exiter interface {
	Exit(int)
}

type osExiter struct{}

func (e osExiter) Exit(code int) {
	os.Exit(code)
}

type Manager struct {
	Commands      map[string]interface{}
	name          string
	stdout        io.Writer
	stderr        io.Writer
	stdin         io.Reader
	version       string
	versionHeader string
	e             exiter
	original      string
	wrong         bool
}

func NewManager(name, ver, verHeader string, stdout, stderr io.Writer, stdin io.Reader) *Manager {
	manager := &Manager{name: name, version: ver, versionHeader: verHeader, stdout: stdout, stderr: stderr, stdin: stdin}
	manager.Register(&help{manager})
	manager.Register(&version{manager})
	return manager
}

func BuildBaseManager(name, version, versionHeader string) *Manager {
	m := NewManager(name, version, versionHeader, os.Stdout, os.Stderr, os.Stdin)
	m.Register(&login{})
	m.Register(&logout{})
	m.Register(&userCreate{})
	m.Register(&userRemove{})
	m.Register(&teamCreate{})
	m.Register(&teamRemove{})
	m.Register(&teamList{})
	m.Register(&teamUserAdd{})
	m.Register(&teamUserRemove{})
	m.Register(&target{})
	return m
}

func (m *Manager) Register(command interface{}) {
	if m.Commands == nil {
		m.Commands = make(map[string]interface{})
	}
	name := command.(Infoer).Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
}

func (m *Manager) Run(args []string) {
	var status int
	if len(args) == 0 {
		args = append(args, "help")
	}
	name := args[0]
	command, ok := m.Commands[name]
	if !ok {
		fmt.Fprintf(m.stderr, "command %s does not exist\n", args[0])
		m.finisher().Exit(1)
		return
	}
	args = args[1:]
	if len(args) < command.(Infoer).Info().MinArgs && name != "help" {
		m.wrong = true
		m.original = command.(Infoer).Info().Name
		command = m.Commands["help"]
		args = []string{name}
		status = 1
	}
	context := Context{args, m.stdout, m.stderr, m.stdin}
	client := NewClient(&http.Client{}, &context, m.version, m.versionHeader)
	err := command.(Command).Run(&context, client)
	if err != nil {
		re := regexp.MustCompile(`^((Invalid token)|(You must provide the Authorization header))`)
		errorMsg := err.Error()
		if re.MatchString(errorMsg) {
			errorMsg = `You're not authenticated or your session has expired. Please use "login" command for authentication.`
		}
		if !strings.HasSuffix(errorMsg, "\n") {
			errorMsg += "\n"
		}
		io.WriteString(m.stderr, errorMsg)
		status = 1
	}
	m.finisher().Exit(status)
}

func (m *Manager) finisher() exiter {
	if m.e == nil {
		m.e = osExiter{}
	}
	return m.e
}

type Infoer interface {
	Info() *Info
}

type Command interface {
	Run(context *Context, client Doer) error
}

type Context struct {
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
	Stdin  io.Reader
}

type Info struct {
	Name    string
	MinArgs int
	Usage   string
	Desc    string
}

type help struct {
	manager *Manager
}

func (c *help) Info() *Info {
	return &Info{
		Name:  "help",
		Usage: "command [args]",
	}
}

func (c *help) Run(context *Context, client Doer) error {
	output := fmt.Sprintf("%s version %s.\n\n", c.manager.name, c.manager.version)
	if c.manager.wrong {
		output += fmt.Sprintf("ERROR: not enough arguments to call %s.\n\n", c.manager.original)
	}
	if len(context.Args) > 0 {
		cmd, ok := c.manager.Commands[context.Args[0]]
		if !ok {
			return fmt.Errorf("Command %s does not exist.", context.Args[0])
		}
		info := cmd.(Infoer).Info()
		output += fmt.Sprintf("Usage: %s %s\n", c.manager.name, info.Usage)
		output += fmt.Sprintf("\n%s\n", info.Desc)
		if info.MinArgs > 0 {
			output += fmt.Sprintf("\nMinimum arguments: %d\n", info.MinArgs)
		}
	} else {
		output += fmt.Sprintf("Usage: %s %s\n\nAvailable commands:\n", c.manager.name, c.Info().Usage)
		var commands []string
		for k := range c.manager.Commands {
			commands = append(commands, k)
		}
		sort.Strings(commands)
		for _, command := range commands {
			output += fmt.Sprintf("  %s\n", command)
		}
		output += fmt.Sprintf("\nRun %s help <commandname> to get more information about a specific command.\n", c.manager.name)
	}
	io.WriteString(context.Stdout, output)
	return nil
}

type version struct {
	manager *Manager
}

func (c *version) Info() *Info {
	return &Info{
		Name:    "version",
		MinArgs: 0,
		Usage:   "version",
		Desc:    "display the current version",
	}
}

func (c *version) Run(context *Context, client Doer) error {
	fmt.Fprintf(context.Stdout, "%s version %s.\n", c.manager.name, c.manager.version)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// validateVersion checks whether current version is greater or equal to
// supported version.
func validateVersion(supported, current string) bool {
	var (
		bigger bool
		limit  int
	)
	partsSupported := strings.Split(supported, ".")
	partsCurrent := strings.Split(current, ".")
	if len(partsSupported) > len(partsCurrent) {
		limit = len(partsCurrent)
		bigger = true
	} else {
		limit = len(partsSupported)
	}
	for i := 0; i < limit; i++ {
		if partsCurrent[i] < partsSupported[i] {
			return false
		}
	}
	if bigger {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
  "redux"
)

var cmdIfCreate = &Command{
   Run: runIfCreate,
	UsageLine: "redux ifcreate [TARGET...]",
	LinkName: "redo-ifcreate",
	Short: "Create dependency on non-existence of targets.",
	Long: `
The ifcreate command creates a dependency on the non-existence of the target files.
The current file will be invalidated if the target comes into existence.
If the target exists, the command returns an error.
`,
}

func runIfCreate(args[]string) {
	redux.RedoIfX(func(file *redux.File, dependent *redux.File) error {
		return file.RedoIfCreate(dependent)
	})
}

var cmdIfChange = &Command{
   Run: runIfChange,
	UsageLine: "redux ifcreate [TARGET...]",
	LinkName: "redo-ifchange",
	Short: "Create dependency on targets and ensure that targets are up to date.",
	Long: `
The ifchange command creates a dependency on the target files and ensures that
the target files are up to date, calling the redo command, if necessary.

The current file will be invalidated if a target is rebuilt.
`,
}

func runIfChange(args[]string) {
	redux.RedoIfX(func(file *redux.File, dependent *redux.File) error {
		return file.RedoIfChange(dependent)
	})
}
<commit_msg>gofmt<commit_after>// Copyright 2014 Gyepi Sam. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"

	"redux"
)

var cmdIfCreate = &Command{
	Run:       runIfCreate,
	UsageLine: "redux ifcreate [TARGET...]",
	LinkName:  "redo-ifcreate",
	Short:     "Creates dependency on non-existence of targets.",
	Long: `
The ifcreate command creates a dependency on the non-existence of the target files.
The current file will be invalidated if the target comes into existence.
If the target exists, the command returns an error.
`,
}

func runIfCreate(args []string) error {
	return redoIfX(args, func(file *redux.File, dependent *redux.File) error {
		return file.RedoIfCreate(dependent)
	})
}

var cmdIfChange = &Command{
	Run:       runIfChange,
	UsageLine: "redux ifchange [TARGET...]",
	LinkName:  "redo-ifchange",
	Short:     "Creates dependency on targets and ensure that targets are up to date.",
	Long: `
The ifchange command creates a dependency on the target files and ensures that
the target files are up to date, calling the redo command, if necessary.

The current file will be invalidated if a target is rebuilt.
`,
}

func runIfChange(args []string) error {
	return redoIfX(args, func(file *redux.File, dependent *redux.File) error {
		return file.RedoIfChange(dependent)
	})
}

func redoIfX(args []string, fn func(*redux.File, *redux.File) error) error {

	dependentPath := os.Getenv(redux.REDO_PARENT_ENV_NAME)
	if len(dependentPath) == 0 {
		return fmt.Errorf("Missing env variable %s", redux.REDO_PARENT_ENV_NAME)
	}

	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	// The action is triggered by dependent.
	dependent, err := redux.NewFile(wd, dependentPath)
	if err != nil {
		return err
	}

	for _, path := range args {
		if file, err := redux.NewFile(wd, path); err != nil {
			return err
		} else if err := fn(file, dependent); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>