package main import ( "flag" "fmt" "html/template" "log" "os" "strings" "time" "github.com/thrasher-/gocryptotrader/common" ) const ( commonPath = "..%s..%scommon%s" communicationsPath = "..%s..%scommunications%s" communicationsBasePath = "..%s..%scommunications%sbase%s" communicationsSlackPath = "..%s..%scommunications%sslack%s" communicationsSmsglobalPath = "..%s..%scommunications%ssmsglobal%s" communicationsSMTPPath = "..%s..%scommunications%ssmtpservice%s" communicationsTelegramPath = "..%s..%scommunications%stelegram%s" configPath = "..%s..%sconfig%s" currencyPath = "..%s..%scurrency%s" currencyFXPath = "..%s..%scurrency%sforexprovider%s" currencyFXBasePath = "..%s..%scurrency%sforexprovider%sbase%s" currencyFXCurrencyConverterPath = "..%s..%scurrency%sforexprovider%scurrencyconverterapi%s" currencyFXCurrencylayerPath = "..%s..%scurrency%sforexprovider%scurrencylayer%s" currencyFXFixerPath = "..%s..%scurrency%sforexprovider%sfixer.io%s" currencyFXOpenExchangeRatesPath = "..%s..%scurrency%sforexprovider%sopenexchangerates%s" currencyPairPath = "..%s..%scurrency%spair%s" currencySymbolPath = "..%s..%scurrency%ssymbol%s" currencyTranslationPath = "..%s..%scurrency%stranslation%s" eventsPath = "..%s..%sevents%s" exchangesPath = "..%s..%sexchanges%s" exchangesNoncePath = "..%s..%sexchanges%snonce%s" exchangesOrderbookPath = "..%s..%sexchanges%sorderbook%s" exchangesStatsPath = "..%s..%sexchanges%sstats%s" exchangesTickerPath = "..%s..%sexchanges%sticker%s" exchangesOrdersPath = "..%s..%sexchanges%sorders%s" exchangesRequestPath = "..%s..%sexchanges%srequest%s" portfolioPath = "..%s..%sportfolio%s" testdataPath = "..%s..%stestdata%s" toolsPath = "..%s..%stools%s" webPath = "..%s..%sweb%s" rootPath = "..%s..%s" // exchange packages alphapoint = "..%s..%sexchanges%salphapoint%s" anx = "..%s..%sexchanges%sanx%s" binance = "..%s..%sexchanges%sbinance%s" bitfinex = "..%s..%sexchanges%sbitfinex%s" bitflyer = "..%s..%sexchanges%sbitflyer%s" bithumb = "..%s..%sexchanges%sbithumb%s" bitmex = "..%s..%sexchanges%sbitmex%s" bitstamp = "..%s..%sexchanges%sbitstamp%s" bittrex = "..%s..%sexchanges%sbittrex%s" btcc = "..%s..%sexchanges%sbtcc%s" btcmarkets = "..%s..%sexchanges%sbtcmarkets%s" coinbasepro = "..%s..%sexchanges%scoinbasepro%s" coinut = "..%s..%sexchanges%scoinut%s" exmo = "..%s..%sexchanges%sexmo%s" gateio = "..%s..%sexchanges%sgateio%s" gemini = "..%s..%sexchanges%sgemini%s" hitbtc = "..%s..%sexchanges%shitbtc%s" huobi = "..%s..%sexchanges%shuobi%s" huobihadax = "..%s..%sexchanges%shuobihadax%s" itbit = "..%s..%sexchanges%sitbit%s" kraken = "..%s..%sexchanges%skraken%s" lakebtc = "..%s..%sexchanges%slakebtc%s" localbitcoins = "..%s..%sexchanges%slocalbitcoins%s" okcoin = "..%s..%sexchanges%sokcoin%s" okex = "..%s..%sexchanges%sokex%s" poloniex = "..%s..%sexchanges%spoloniex%s" yobit = "..%s..%sexchanges%syobit%s" zb = "..%s..%sexchanges%szb%s" contributorsList = "https://api.github.com/repos/thrasher-/gocryptotrader/contributors" licenseName = "LICENSE" contributorName = "CONTRIBUTORS" ) var ( verbose, replace bool codebasePaths map[string]string codebaseTemplatePath map[string]string codebaseReadme map[string]readme tmpl *template.Template path string contributors []contributor ) type readme struct { Name string Contributors []contributor NameURL string Year int CapitalName string } type contributor struct { Login string `json:"login"` URL string `json:"html_url"` Contributions int `json:"contributions"` } func main() { flag.BoolVar(&verbose, "v", false, "-v Verbose flag prints more information to the std output") flag.BoolVar(&replace, "r", false, "-r Replace flag generates and replaces all documentation across the code base") flag.Parse() fmt.Println(` GoCryptoTrader: Exchange documentation tool This will update and regenerate documentation for the different packages in GoCryptoTrader.`) codebasePaths = make(map[string]string) codebaseTemplatePath = make(map[string]string) codebaseReadme = make(map[string]readme) path = common.GetOSPathSlash() if err := getContributorList(); err != nil { log.Fatal("GoCryptoTrader: Exchange documentation tool GET error ", err) } fmt.Println("Contributor list fetched") if err := addTemplates(); err != nil { log.Fatal("GoCryptoTrader: Exchange documentation tool add template error ", err) } fmt.Println("Templates parsed") if err := updateReadme(); err != nil { log.Fatal("GoCryptoTrader: Exchange documentation tool update readme error ", err) } fmt.Println("\nTool finished") } // updateReadme iterates through codebase paths to check for readme files and either adds // or replaces with new readme files. func updateReadme() error { addPaths() for packageName := range codebasePaths { addReadmeData(packageName) if !checkReadme(packageName) { if verbose { fmt.Printf("* %s Readme file FOUND.\n", packageName) } if replace { if verbose { fmt.Println("file replacement") } if err := replaceReadme(packageName); err != nil { return err } continue } continue } if verbose { fmt.Printf("* %s Readme file NOT FOUND.\n", packageName) } if replace { if verbose { log.Println("file creation") } if err := createReadme(packageName); err != nil { return err } continue } } return nil } // addPaths adds paths to different potential README.md files in the codebase func addPaths() { codebasePaths["common"] = fmt.Sprintf(commonPath, path, path, path) codebasePaths["communications comms"] = fmt.Sprintf(communicationsPath, path, path, path) codebasePaths["communications base"] = fmt.Sprintf(communicationsBasePath, path, path, path, path) codebasePaths["communications slack"] = fmt.Sprintf(communicationsSlackPath, path, path, path, path) codebasePaths["communications smsglobal"] = fmt.Sprintf(communicationsSmsglobalPath, path, path, path, path) codebasePaths["communications smtp"] = fmt.Sprintf(communicationsSMTPPath, path, path, path, path) codebasePaths["communications telegram"] = fmt.Sprintf(communicationsTelegramPath, path, path, path, path) codebasePaths["config"] = fmt.Sprintf(configPath, path, path, path) codebasePaths["currency"] = fmt.Sprintf(currencyPath, path, path, path) codebasePaths["currency forexprovider"] = fmt.Sprintf(currencyFXPath, path, path, path, path) codebasePaths["currency forexprovider base"] = fmt.Sprintf(currencyFXBasePath, path, path, path, path, path) codebasePaths["currency forexprovider currencyconverter"] = fmt.Sprintf(currencyFXCurrencyConverterPath, path, path, path, path, path) codebasePaths["currency forexprovider currencylayer"] = fmt.Sprintf(currencyFXCurrencylayerPath, path, path, path, path, path) codebasePaths["currency forexprovider fixer"] = fmt.Sprintf(currencyFXFixerPath, path, path, path, path, path) codebasePaths["currency forexprovider openexchangerates"] = fmt.Sprintf(currencyFXOpenExchangeRatesPath, path, path, path, path, path) codebasePaths["currency pair"] = fmt.Sprintf(currencyPairPath, path, path, path, path) codebasePaths["currency symbol"] = fmt.Sprintf(currencySymbolPath, path, path, path, path) codebasePaths["currency translation"] = fmt.Sprintf(currencyTranslationPath, path, path, path, path) codebasePaths["events"] = fmt.Sprintf(eventsPath, path, path, path) codebasePaths["portfolio"] = fmt.Sprintf(portfolioPath, path, path, path) codebasePaths["testdata"] = fmt.Sprintf(testdataPath, path, path, path) codebasePaths["tools"] = fmt.Sprintf(toolsPath, path, path, path) codebasePaths["web"] = fmt.Sprintf(webPath, path, path, path) codebasePaths["root"] = fmt.Sprintf(rootPath, path, path) codebasePaths["exchanges"] = fmt.Sprintf(exchangesPath, path, path, path) codebasePaths["exchanges nonce"] = fmt.Sprintf(exchangesNoncePath, path, path, path, path) codebasePaths["exchanges orderbook"] = fmt.Sprintf(exchangesOrderbookPath, path, path, path, path) codebasePaths["exchanges stats"] = fmt.Sprintf(exchangesStatsPath, path, path, path, path) codebasePaths["exchanges ticker"] = fmt.Sprintf(exchangesTickerPath, path, path, path, path) codebasePaths["exchanges orders"] = fmt.Sprintf(exchangesOrdersPath, path, path, path, path) codebasePaths["exchanges request"] = fmt.Sprintf(exchangesRequestPath, path, path, path, path) codebasePaths["exchanges alphapoint"] = fmt.Sprintf(alphapoint, path, path, path, path) codebasePaths["exchanges anx"] = fmt.Sprintf(anx, path, path, path, path) codebasePaths["exchanges binance"] = fmt.Sprintf(binance, path, path, path, path) codebasePaths["exchanges bitfinex"] = fmt.Sprintf(bitfinex, path, path, path, path) codebasePaths["exchanges bitflyer"] = fmt.Sprintf(bitflyer, path, path, path, path) codebasePaths["exchanges bithumb"] = fmt.Sprintf(bithumb, path, path, path, path) codebasePaths["exchanges bitmex"] = fmt.Sprintf(bitmex, path, path, path, path) codebasePaths["exchanges bitstamp"] = fmt.Sprintf(bitstamp, path, path, path, path) codebasePaths["exchanges bittrex"] = fmt.Sprintf(bittrex, path, path, path, path) codebasePaths["exchanges btcc"] = fmt.Sprintf(btcc, path, path, path, path) codebasePaths["exchanges btcmarkets"] = fmt.Sprintf(btcmarkets, path, path, path, path) codebasePaths["exchanges coinut"] = fmt.Sprintf(coinut, path, path, path, path) codebasePaths["exchanges exmo"] = fmt.Sprintf(exmo, path, path, path, path) codebasePaths["exchanges coinbasepro"] = fmt.Sprintf(coinbasepro, path, path, path, path) codebasePaths["exchanges gateio"] = fmt.Sprintf(gateio, path, path, path, path) codebasePaths["exchanges gemini"] = fmt.Sprintf(gemini, path, path, path, path) codebasePaths["exchanges hitbtc"] = fmt.Sprintf(hitbtc, path, path, path, path) codebasePaths["exchanges huobi"] = fmt.Sprintf(huobi, path, path, path, path) codebasePaths["exchanges huobihadax"] = fmt.Sprintf(huobihadax, path, path, path, path) codebasePaths["exchanges itbit"] = fmt.Sprintf(itbit, path, path, path, path) codebasePaths["exchanges kraken"] = fmt.Sprintf(kraken, path, path, path, path) codebasePaths["exchanges lakebtc"] = fmt.Sprintf(lakebtc, path, path, path, path) codebasePaths["exchanges localbitcoins"] = fmt.Sprintf(localbitcoins, path, path, path, path) codebasePaths["exchanges okcoin"] = fmt.Sprintf(okcoin, path, path, path, path) codebasePaths["exchanges okex"] = fmt.Sprintf(okex, path, path, path, path) codebasePaths["exchanges poloniex"] = fmt.Sprintf(poloniex, path, path, path, path) codebasePaths["exchanges yobit"] = fmt.Sprintf(yobit, path, path, path, path) codebasePaths["exchanges zb"] = fmt.Sprintf(zb, path, path, path, path) codebasePaths["CONTRIBUTORS"] = fmt.Sprintf(rootPath, path, path) codebasePaths["LICENSE"] = fmt.Sprintf(rootPath, path, path) } func addReadmeData(packageName string) { readmeInfo := readme{ Name: getName(packageName, false), Contributors: contributors, NameURL: getslashFromName(packageName), Year: time.Now().Year(), CapitalName: getName(packageName, true), } codebaseReadme[packageName] = readmeInfo } func getName(name string, capital bool) string { newStrings := strings.Split(name, " ") if len(newStrings) > 1 { if capital { return getCapital(newStrings[1]) } return newStrings[1] } if capital { return getCapital(name) } return name } func getCapital(name string) string { capLetter := strings.ToUpper(string(name[0])) last := name[1:] return capLetter + last } // getslashFromName returns a string for godoc package names func getslashFromName(packageName string) string { if strings.Contains(packageName, " ") { s := strings.Split(packageName, " ") return strings.Join(s, "/") } if packageName == "testdata" || packageName == "tools" || packageName == contributorName || packageName == licenseName { return "" } return packageName } var globS = []string{ fmt.Sprintf("common_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("communications_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("config_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("currency_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("events_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("exchanges_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("portfolio_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("root_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("sub_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("testdata_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("tools_templates%s*", common.GetOSPathSlash()), fmt.Sprintf("web_templates%s*", common.GetOSPathSlash()), } // addTemplates adds all the template files func addTemplates() error { tmpl = template.New("") for _, s := range globS { _, err := tmpl.ParseGlob(s) if err != nil { return err } } return nil } // checkReadme checks to see if the file exists func checkReadme(packageName string) bool { if packageName == licenseName || packageName == contributorName { _, err := os.Stat(codebasePaths[packageName] + packageName) return os.IsNotExist(err) } _, err := os.Stat(codebasePaths[packageName] + "README.md") return os.IsNotExist(err) } // replaceReadme replaces readme file func replaceReadme(packageName string) error { if packageName == licenseName || packageName == contributorName { if err := deleteFile(codebasePaths[packageName] + packageName); err != nil { return err } return createReadme(packageName) } if err := deleteFile(codebasePaths[packageName] + "README.md"); err != nil { return err } return createReadme(packageName) } // createReadme creates new readme file and executes template func createReadme(packageName string) error { if packageName == licenseName || packageName == contributorName { file, err := os.Create(codebasePaths[packageName] + packageName) if err != nil { return err } defer file.Close() if verbose { fmt.Println("File done") } return tmpl.ExecuteTemplate(file, packageName, codebaseReadme[packageName]) } file, err := os.Create(codebasePaths[packageName] + "README.md") if err != nil { return err } defer file.Close() if verbose { fmt.Println("File done") } return tmpl.ExecuteTemplate(file, packageName, codebaseReadme[packageName]) } func deleteFile(path string) error { return os.Remove(path) } func getContributorList() error { return common.SendHTTPGetRequest(contributorsList, true, false, &contributors) }