Ejemplo n.º 1
0
func (c Config) Load() (err error) {
	err = InitPath(ConfigPath)
	if err != nil {
		return
	}

	// If stat cannot be calculated, ConfigPath does not exist. This is not an error.
	if _, err = os.Stat(ConfigPath); err != nil {
		err = nil
		return
	}

	byt, err := ioutil.ReadFile(ConfigPath)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("access error to config path '%s': %s", ConfigPath, err))
		return
	}

	var rawConfig []SiteConfig
	err = json.Unmarshal(byt, &rawConfig)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("config path '%s' is corrupted: %s", ConfigPath, err))
		return
	}

	for _, siteConfig := range rawConfig {
		c[siteConfig.Host] = siteConfig
	}

	return
}
Ejemplo n.º 2
0
func RemoteURL(dir string) (parsed *remoteURL, err error) {
	cmd := exec.Command("git", "remote", "-v")
	cmd.Dir = dir
	out, cmdErr := cmd.Output()
	outStr := string(out)

	if cmdErr != nil {
		msg := fmt.Sprintf("can not exec 'git remove -v' : %s", cmdErr)
		err = util.LyciaError(msg)

	} else if outStr == "" {
		err = util.LyciaError("git remote is not defined")

	} else if !remoteUrlPattern.MatchString(outStr) {
		msg := fmt.Sprintf("unknown git remote string: %s", outStr)
		err = util.LyciaError(msg)

	} else {
		rawUrl := remoteUrlPattern.FindStringSubmatch(outStr)[1]
		gitUrl, _ := UrlMaker(rawUrl)
		parsedURL, err := url.Parse(gitUrl.WebUrl)
		if err == nil {
			parsed = &remoteURL{"", parsedURL}
		}
	}
	return
}
Ejemplo n.º 3
0
func (c Cache) SaveCache() (err error) {
	err = InitPath(CachePath)
	if err != nil {
		return
	}

	var rawCache []PrUrlCache
	for repositoryUrl, cache := range c {
		for branch, prUrl := range cache {
			rawCache = append(rawCache, PrUrlCache{repositoryUrl, branch, prUrl})
		}
	}

	byt, err := json.Marshal(rawCache)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cannot encode cache to JSON: %s", err))
		return
	}

	err = ioutil.WriteFile(CachePath, byt, 0644)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cannot write cache to file '%s': %s", CachePath, err))
	}

	return
}
Ejemplo n.º 4
0
func (repo *repository) PullrequestUrlWithBranch(branch string, force bool) (prURL *url.URL, err error) {
	if !force {
		prURL, err = repo.GetPrUrlFromCache(branch)
		if err == nil {
			return
		}
	}

	values := url.Values{}
	repoPath := strings.TrimLeft(repo.URL.Path, "/")
	queryString := fmt.Sprintf("repo:%s type:pr head:%s", repoPath, branch)
	values.Add("q", queryString)

	apiRoot, err := repo.DetectApiRootAndSetAccessToken(values)
	if err != nil {
		err = util.LyciaError("cannot detect ApiRoot: " + err.Error())
		return
	}

	searchURL := fmt.Sprintf("%s/search/issues?%s", apiRoot, values.Encode())
	res, err := http.Get(searchURL)
	if err != nil {
		err = util.LyciaError("failed to fetch: " + searchURL)
		return
	}

	defer res.Body.Close()

	decoder := json.NewDecoder(res.Body)

	var searchIssues SearchIssues
	if err = decoder.Decode(&searchIssues); err != nil {
		return
	}

	items := searchIssues.Items
	if len(items) == 0 {
		err = util.LyciaError(fmt.Sprintf("pullrequest not found for the branch: %s", branch))
		return
	}

	prURL, err = url.Parse(items[0].HtmlUrl)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("html_url is invalid: %s", items[0].HtmlUrl))
		return
	}

	err = repo.SavePrUrlToCache(branch, prURL)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cache cannot be saved: %s", err))
	}

	return
}
Ejemplo n.º 5
0
func parseTmuxEnv() (setting Setting, err error) {
	showenvCommand := _exec.Command("tmux", "showenv")
	stdout, err := showenvCommand.StdoutPipe()
	if err != nil {
		err = util.LyciaError(err.Error())
		return
	}

	err = showenvCommand.Start()
	if err != nil {
		err = util.LyciaError(err.Error())
		return
	}

	scanner := bufio.NewScanner(stdout)
	const sep = "="
	const prefix = "LC_FSSH_"
	var port, user, copyArgs, path string
	for scanner.Scan() {
		keyAndValue := strings.SplitN(scanner.Text(), sep, 2)
		if len(keyAndValue) != 2 {
			continue
		}

		key := keyAndValue[0]
		value := keyAndValue[1]
		if -1 == strings.Index(key, prefix) {
			continue
		}

		switch key[len(prefix):] {
		case "PORT":
			port = value
		case "USER":
			user = value
		case "COPY_ARGS":
			copyArgs = value
		case "PATH":
			path = value
		}
	}

	err = showenvCommand.Wait()
	if err != nil {
		err = util.LyciaError(err.Error())
		return
	}

	if len(port) > 0 && len(user) > 0 && len(copyArgs) > 0 && len(path) > 0 {
		setting = Setting{port, user, copyArgs, path}
	}
	return
}
Ejemplo n.º 6
0
func (repo *repository) GetPrUrlFromCache(branch string) (prURL *url.URL, err error) {
	branchToUrl, ok := repo.Cache[repo.URL.String()]
	if !ok {
		err = util.LyciaError("cache not found")
		return
	}
	if prUrlStr, ok := branchToUrl[branch]; ok {
		prURL, err = url.Parse(prUrlStr)
	} else {
		err = util.LyciaError("cache not found")
	}
	return
}
Ejemplo n.º 7
0
func DetectCurrentBranch(dir string) (branch string) {
	cmd := exec.Command("git", "branch")
	cmd.Dir = dir
	out, err := cmd.Output()

	if err != nil {
		err = util.LyciaError("can not exec 'git branch'")
		return
	}
	if !branchPattern.Match(out) {
		err = util.LyciaError("can not detect branch")
		return
	}
	branch = string(branchPattern.FindSubmatch(out)[1])
	return
}
Ejemplo n.º 8
0
func InitPath(pathStr string) (err error) {
	dir, _ := path.Split(pathStr)
	stat, err := os.Stat(dir)
	if err != nil || !stat.IsDir() {
		err = os.MkdirAll(dir, 0755)
		if err != nil {
			err = util.LyciaError(fmt.Sprintf("cannot mkdir: '%s'", dir))
			return
		}
	}
	return
}
Ejemplo n.º 9
0
func (c Cache) LoadCache() (err error) {
	err = InitPath(CachePath)
	if err != nil {
		return
	}

	// If stat cannot be calculated, CachePath does not exist. This is not an error.
	if _, err = os.Stat(CachePath); err != nil {
		err = nil
		return
	}

	byt, err := ioutil.ReadFile(CachePath)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("access error to cache path '%s': %s", CachePath, err))
		return
	}

	var rawCache []PrUrlCache
	err = json.Unmarshal(byt, &rawCache)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cache path '%s' is corrupted: %s", CachePath, err))
		return
	}

	for _, prUrlCache := range rawCache {
		var branchToUrl BranchToUrl
		if c[prUrlCache.RepositoryUrl] == nil {
			branchToUrl = make(BranchToUrl)
			c[prUrlCache.RepositoryUrl] = branchToUrl
		} else {
			branchToUrl = c[prUrlCache.RepositoryUrl]
		}
		branchToUrl[prUrlCache.Branch] = prUrlCache.PrUrl
	}

	return
}
Ejemplo n.º 10
0
func (c Config) Save() (err error) {
	err = InitPath(ConfigPath)
	if err != nil {
		return
	}

	var rawConfig []SiteConfig
	for _, config := range c {
		rawConfig = append(rawConfig, config)
	}

	byt, err := json.Marshal(rawConfig)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cannot encode config to JSON: %s", err))
		return
	}

	err = ioutil.WriteFile(ConfigPath, byt, 0644)
	if err != nil {
		err = util.LyciaError(fmt.Sprintf("cannot write config to file '%s': %s", ConfigPath, err))
	}
	return
}
Ejemplo n.º 11
0
// Command is to execute any commands with FSSH
func Command(name string, args ...string) (cmd *exec.Cmd, err error) {
	empty := Setting{}
	var fsshEnv Setting
	if fsshEnv, err = fetchFsshEnv(); err != nil {
		err = util.LyciaError(err.Error())
		return
	} else if fsshEnv != empty {
		commandToExecute := strings.Join(append([]string{name}, args...), " ")
		name = "ssh"
		args = fsshEnv.sshArgs(commandToExecute)
	}
	cmd = _exec.Command(name, args...)
	return
}
Ejemplo n.º 12
0
func (repo *repository) DetectApiRootAndSetAccessToken(values url.Values) (apiRoot string, err error) {
	if repo.URL.Host == "github.com" {
		apiRoot = "https://api.github.com"
		return
	}

	if v, ok := repo.Config[repo.URL.Host]; ok {
		apiRoot = v.ApiRoot
		values.Add("access_token", v.AccessToken)
		return
	}

	sc := SiteConfig{repo.URL.Host, "", ""}

	msg := fmt.Sprintf("Please input github API root path for '%s' (such as 'https://api.github.com') :", repo.URL.Host)
	apiRoot, err = ask.Ask(msg, false)
	if err != nil {
		return
	}
	sc.ApiRoot = strings.TrimLeft(apiRoot, "/")

	sc.AccessToken, err = repo.NewAccessToken(sc.Host, sc.ApiRoot)
	if err != nil {
		err = util.LyciaError("failed to generate new access token: " + err.Error())
		return
	}

	repo.Config[repo.URL.Host] = sc
	err = repo.Config.Save()
	if err != nil {
		err = util.LyciaError("failed to save config: " + err.Error())
		return
	}

	values.Add("access_token", sc.AccessToken)
	return
}
Ejemplo n.º 13
0
func (gitUrl *GitUrl) Parse() (err error) {
	if !urlPattern.MatchString(gitUrl.RawUrl) {
		return util.LyciaError("this is not URL for git")
	}
	names := urlPattern.SubexpNames()[1:]
	m := urlPattern.FindStringSubmatch(gitUrl.RawUrl)[1:]
	matches := make(map[string]string)
	for i, str := range m {
		matches[names[i]] = str
	}
	gitUrl.Scheme = matches["scheme"]
	gitUrl.Username = matches["username"]
	gitUrl.Host = matches["host"]
	gitUrl.Path = matches["path"]
	return
}
Ejemplo n.º 14
0
func (repo *repository) NewAccessToken(host string, apiRoot string) (accessToken string, err error) {
	username, err := ask.Ask(fmt.Sprintf("Please input username for '%s':", host), false)
	if err != nil {
		return
	}
	password, err := ask.Ask(fmt.Sprintf("Please input password for '%s':", host), true)
	if err != nil {
		return
	}

	reqBody := fmt.Sprintf(`{"scopes":["repo"],"note":"lycia %s"}`, time.Now())
	req, err := repo.NewPostRequest(username, password, apiRoot+"/authorizations", reqBody)
	if err != nil {
		return
	}

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return
	}

	if res.StatusCode == 401 {
		if v := res.Header.Get("X-Github-Otp"); strings.HasPrefix(v, "required;") {
			var otp string
			otp, err = ask.Ask("Please input two-factor authentication code:", false)
			if err != nil {
				return
			}

			req, err = repo.NewPostRequest(username, password, apiRoot+"/authorizations", reqBody)
			if err != nil {
				return
			}
			req.Header.Add("X-Github-Otp", otp)
			res, err = client.Do(req)
			if err != nil {
				return
			}

		} else {
			err = util.LyciaError("Bad credentials")
			return
		}

	} else if res.StatusCode != 200 && res.StatusCode != 201 {
		err = util.LyciaError(fmt.Sprintf("Unknown status: %s", res.Status))
		return
	}

	defer res.Body.Close()

	decoder := json.NewDecoder(res.Body)

	var authorizations Authorizations
	if err = decoder.Decode(&authorizations); err != nil {
		return
	}

	if authorizations.HashedToken != "" {
		accessToken = authorizations.HashedToken
	} else if authorizations.Token != "" {
		accessToken = authorizations.Token
	} else {
		err = util.LyciaError("cannot detect HashedToken")
	}
	return
}