gogs/internal/cmd/import.go

112 lines
2.9 KiB
Go

// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"bufio"
"bytes"
"fmt"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
"github.com/unknwon/com"
"github.com/urfave/cli"
"gogs.io/gogs/internal/conf"
)
var (
Import = cli.Command{
Name: "import",
Usage: "Import portable data as local Gogs data",
Description: `Allow user import data from other Gogs installations to local instance
without manually hacking the data files`,
Subcommands: []cli.Command{
subcmdImportLocale,
},
}
subcmdImportLocale = cli.Command{
Name: "locale",
Usage: "Import locale files to local repository",
Action: runImportLocale,
Flags: []cli.Flag{
stringFlag("source", "", "Source directory that stores new locale files"),
stringFlag("target", "", "Target directory that stores old locale files"),
stringFlag("config, c", "", "Custom configuration file path"),
},
}
)
func runImportLocale(c *cli.Context) error {
if !c.IsSet("source") {
return errors.New("source directory is not specified")
} else if !c.IsSet("target") {
return errors.New("target directory is not specified")
}
if !com.IsDir(c.String("source")) {
return fmt.Errorf("source directory %q does not exist or is not a directory", c.String("source"))
} else if !com.IsDir(c.String("target")) {
return fmt.Errorf("target directory %q does not exist or is not a directory", c.String("target"))
}
err := conf.Init(c.String("config"))
if err != nil {
return errors.Wrap(err, "init configuration")
}
now := time.Now()
var line []byte
badChars := []byte(`="`)
escapedQuotes := []byte(`\"`)
regularQuotes := []byte(`"`)
// Cut out en-US.
for _, lang := range conf.I18n.Langs[1:] {
name := fmt.Sprintf("locale_%s.ini", lang)
source := filepath.Join(c.String("source"), name)
target := filepath.Join(c.String("target"), name)
if !com.IsFile(source) {
continue
}
// Crowdin surrounds double quotes for strings contain quotes inside,
// this breaks INI parser, we need to fix that.
sr, err := os.Open(source)
if err != nil {
return fmt.Errorf("open: %v", err)
}
tw, err := os.Create(target)
if err != nil {
return fmt.Errorf("create: %v", err)
}
scanner := bufio.NewScanner(sr)
for scanner.Scan() {
line = scanner.Bytes()
idx := bytes.Index(line, badChars)
if idx > -1 && line[len(line)-1] == '"' {
// We still want the "=" sign
line = append(line[:idx+1], line[idx+2:len(line)-1]...)
line = bytes.ReplaceAll(line, escapedQuotes, regularQuotes)
}
_, _ = tw.Write(line)
_, _ = tw.WriteString("\n")
}
_ = sr.Close()
_ = tw.Close()
// Modification time of files from Crowdin often ahead of current,
// so we need to set back to current.
_ = os.Chtimes(target, now, now)
}
fmt.Println("Locale files has been successfully imported!")
return nil
}