You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
4.9 KiB
197 lines
4.9 KiB
package main |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"github.com/jonasfranz/drone-crowdin/responses" |
|
"github.com/jonasfranz/drone-crowdin/utils" |
|
"io" |
|
"mime/multipart" |
|
"net/http" |
|
"os" |
|
) |
|
|
|
type ( |
|
// Files is a mapping between the crowdin path and the real file path |
|
Files map[string]string |
|
|
|
// Config stores the credentials for the crowdin API |
|
Config struct { |
|
Key string |
|
Identifier string |
|
} |
|
|
|
// Plugin represents the drone-crowdin plugin including config and file-mapping. |
|
Plugin struct { |
|
Config Config |
|
Files Files |
|
Branch string |
|
Languages []string |
|
ExportDirectory string |
|
DoDownload bool |
|
} |
|
) |
|
|
|
// ToProjectURL returns the base URL of the api endpoint |
|
func (c Config) ToProjectURL() string { |
|
return fmt.Sprintf("https://api.crowdin.com/api/project/%s", c.Identifier) |
|
} |
|
|
|
// ToUploadURL returns the API-endpoint including identifier and API-KEY |
|
func (c Config) ToUploadURL() string { |
|
return fmt.Sprintf("%s/update-file?key=%s", c.ToProjectURL(), c.Key) |
|
} |
|
|
|
// ToLanguageDownloadURL returns the download endpoint for the given language |
|
func (p Plugin) ToLanguageDownloadURL(language string) string { |
|
if p.Branch != "" { |
|
return fmt.Sprintf("%s/download/%s.zip?key=%s&branch=%s", p.Config.ToProjectURL(), language, p.Config.Key, p.Branch) |
|
} |
|
return fmt.Sprintf("%s/download/%s.zip?key=%s", p.Config.ToProjectURL(), language, p.Config.Key) |
|
|
|
} |
|
|
|
// Exec starts the plugin and updates the crowdin translation by uploading files from the files map |
|
func (p Plugin) Exec() error { |
|
client := &http.Client{} |
|
|
|
//SECTION: Upload |
|
if len(p.Files) > 20 { |
|
return fmt.Errorf("20 files max are allowed to upload. %d files given", len(p.Files)) |
|
} else if len(p.Files) > 0 { |
|
req, err := p.buildUploadRequest() |
|
if err != nil { |
|
return fmt.Errorf("error while building upload request: %v", err) |
|
} |
|
resp, err := client.Do(req) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
body := &bytes.Buffer{} |
|
if _, err := body.ReadFrom(resp.Body); err != nil { |
|
return err |
|
} |
|
if err := resp.Body.Close(); err != nil { |
|
return err |
|
} |
|
if resp.StatusCode != 200 { |
|
if e, err := responses.ParseAsError(body); err != nil { |
|
return err |
|
} else { |
|
return fmt.Errorf("error while uploading: %v", e) |
|
} |
|
} |
|
var success = new(responses.Success) |
|
if success, err = responses.ParseAsSuccess(body); err != nil { |
|
return err |
|
} |
|
for _, file := range success.Stats { |
|
fmt.Printf("%s: %s\n", file.Name, file.Status) |
|
} |
|
} |
|
|
|
//SECTION: Download |
|
if p.DoDownload { |
|
if err := p.buildTranslations(client); err != nil { |
|
return fmt.Errorf("error while building languages: %v", err) |
|
} |
|
for _, language := range p.Languages { |
|
if err := p.downloadLanguage(client, language); err != nil { |
|
return fmt.Errorf("error while downloading %s: %v", language, err) |
|
} |
|
fmt.Printf("Downloaded package: %s\n", language) |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func (p Plugin) buildUploadRequest() (*http.Request, error) { |
|
body := &bytes.Buffer{} |
|
writer := multipart.NewWriter(body) |
|
for crowdinPath, path := range p.Files { |
|
var err error |
|
var file *os.File |
|
if file, err = os.Open(path); err != nil { |
|
return nil, err |
|
} |
|
defer file.Close() |
|
|
|
part, err := writer.CreateFormFile(fmt.Sprintf("files[%s]", crowdinPath), crowdinPath) |
|
if err != nil { |
|
return nil, err |
|
} |
|
if _, err = io.Copy(part, file); err != nil { |
|
return nil, err |
|
} |
|
} |
|
// Adding branch if it is not ignored |
|
if p.Branch != "" { |
|
writer.WriteField("branch", p.Branch) |
|
} |
|
if err := writer.Close(); err != nil { |
|
return nil, err |
|
} |
|
var req *http.Request |
|
var err error |
|
if req, err = http.NewRequest("POST", p.Config.ToUploadURL(), body); err != nil { |
|
return nil, err |
|
} |
|
req.Header.Set("Content-Type", writer.FormDataContentType()) |
|
return req, nil |
|
} |
|
|
|
func (p Plugin) buildTranslations(client *http.Client) error { |
|
// Step 1: Export translations (aka generate server side) |
|
exportURL := fmt.Sprintf("%s/export?key=%s", p.Config.ToProjectURL(), p.Config.Key) |
|
if p.Branch != "" { |
|
exportURL = fmt.Sprintf("%s&branch=%s", exportURL, p.Branch) |
|
} |
|
if resp, err := client.Get(exportURL); err != nil { |
|
return err |
|
} else if resp.StatusCode != 200 { |
|
defer resp.Body.Close() |
|
if e, err := responses.ParseAsError(resp.Body); err != nil { |
|
return err |
|
} else { |
|
return e |
|
} |
|
} else { |
|
defer resp.Body.Close() |
|
} |
|
return nil |
|
} |
|
|
|
func (p Plugin) downloadLanguage(client *http.Client, language string) error { |
|
file, err := downloadFromUrl(p.ToLanguageDownloadURL(language)) |
|
if err != nil { |
|
return err |
|
} |
|
err = utils.Unzip(file.Name(), p.ExportDirectory) |
|
if err != nil { |
|
return err |
|
} |
|
err = os.Remove(file.Name()) |
|
if err != nil { |
|
return err |
|
} |
|
return nil |
|
} |
|
|
|
func downloadFromUrl(url string) (*os.File, error) { |
|
output, err := os.Create("lang.zip") |
|
if err != nil { |
|
return nil, err |
|
} |
|
defer output.Close() |
|
|
|
response, err := http.Get(url) |
|
if err != nil { |
|
os.Remove(output.Name()) |
|
return nil, err |
|
} |
|
defer response.Body.Close() |
|
|
|
_, err = io.Copy(output, response.Body) |
|
return output, err |
|
}
|
|
|