Skip to content
This repository was archived by the owner on Apr 8, 2024. It is now read-only.

Commit f96562e

Browse files
committed
feat(server): add tool to migrate uc v1 data and upload assets
1 parent ddaf076 commit f96562e

File tree

9 files changed

+312
-50
lines changed

9 files changed

+312
-50
lines changed

Diff for: go.work.sum

+1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
470470
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
471471
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700=
472472
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=
473+
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
473474
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
474475
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
475476
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=

Diff for: server/main.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212

1313
"github.com/eukarya-inc/reearth-plateauview/server/putil"
14+
"github.com/eukarya-inc/reearth-plateauview/server/tool"
1415
"github.com/go-playground/validator/v10"
1516
"github.com/labstack/echo/v4"
1617
"github.com/labstack/echo/v4/middleware"
@@ -27,7 +28,10 @@ func main() {
2728
conf := lo.Must(NewConfig())
2829

2930
if len(os.Args) > 1 && os.Args[1] != "" {
30-
tool(conf, os.Args[1:])
31+
tool.Main(&tool.Config{
32+
CMS_BaseURL: conf.CMS_BaseURL,
33+
CMS_Token: conf.CMS_Token,
34+
}, os.Args[1:])
3135
return
3236
}
3337

Diff for: server/tool/migrate-v1.go

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package tool
2+
3+
import (
4+
"archive/zip"
5+
"flag"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"net/url"
10+
"os"
11+
"path"
12+
"path/filepath"
13+
"regexp"
14+
"strings"
15+
)
16+
17+
func migrateV1(conf *Config, args []string) error {
18+
var listFilePath, output, baseURL string
19+
var offset int
20+
var wetrun bool
21+
22+
flags := flag.NewFlagSet("migrate-v1", flag.ExitOnError)
23+
flags.StringVar(&listFilePath, "list", "", "list file path")
24+
flags.StringVar(&output, "output", "", "output file path")
25+
flags.StringVar(&baseURL, "base", "", "base URL")
26+
flags.BoolVar(&wetrun, "wetrun", false, "wet run")
27+
flags.IntVar(&offset, "offset", 0, "offset")
28+
if err := flags.Parse(args); err != nil {
29+
return err
30+
}
31+
32+
if baseURL == "" {
33+
return fmt.Errorf("base URL is required")
34+
}
35+
36+
if output != "" {
37+
_ = os.MkdirAll(output, 0755)
38+
}
39+
40+
listFile, err := os.ReadFile(listFilePath)
41+
if err != nil {
42+
return fmt.Errorf("failed to read list file: %w", err)
43+
}
44+
45+
list, err := parseList(listFile)
46+
47+
if offset > 0 {
48+
if len(list) < offset {
49+
return fmt.Errorf("offset is too large")
50+
}
51+
list = list[offset:]
52+
}
53+
54+
le := len(list)
55+
if err != nil {
56+
return fmt.Errorf("failed to parse list: %w", err)
57+
}
58+
59+
var file *os.File
60+
var zw *zip.Writer
61+
62+
exhangeZw := func(g string) error {
63+
if zw != nil {
64+
if err := zw.Close(); err != nil {
65+
return fmt.Errorf("failed to close zip: %w", err)
66+
}
67+
}
68+
69+
if file != nil {
70+
if err := file.Close(); err != nil {
71+
return fmt.Errorf("failed to close file: %w", err)
72+
}
73+
}
74+
75+
if g == "" {
76+
zw = nil
77+
file = nil
78+
return nil
79+
}
80+
81+
file, err = os.OpenFile(filepath.Join(output, g+".zip"), os.O_CREATE|os.O_WRONLY, 0644)
82+
if err != nil {
83+
return fmt.Errorf("failed to open file: %w", err)
84+
}
85+
86+
zw = zip.NewWriter(file)
87+
return nil
88+
}
89+
90+
defer func() {
91+
if zw != nil {
92+
_ = zw.Close()
93+
}
94+
if file != nil {
95+
_ = file.Close()
96+
}
97+
}()
98+
99+
group := ""
100+
for i, p := range list {
101+
g := p[1]
102+
filePath := path.Join(p[2:]...)
103+
path := filepath.Join(p...)
104+
u, err := url.JoinPath(baseURL, path)
105+
if err != nil {
106+
return fmt.Errorf("failed to join path: %w", err)
107+
}
108+
109+
fmt.Printf("%d/%d | %s | %s | %s\n", i+1, le, g, filePath, u)
110+
111+
if group != g {
112+
fmt.Printf("group: %s\n", g)
113+
114+
if wetrun {
115+
if err := exhangeZw(g); err != nil {
116+
return err
117+
}
118+
}
119+
120+
group = g
121+
}
122+
123+
if wetrun {
124+
if err := downloadAndAddToZip(zw, path, u, filePath); err != nil {
125+
return fmt.Errorf("failed to download: %w", err)
126+
}
127+
}
128+
}
129+
130+
if err := exhangeZw(""); err != nil {
131+
return err
132+
}
133+
134+
return nil
135+
}
136+
137+
func downloadAndAddToZip(zw *zip.Writer, path, url, filePath string) error {
138+
req, err := http.NewRequest("GET", url, nil)
139+
if err != nil {
140+
return fmt.Errorf("failed to create request: %w", err)
141+
}
142+
143+
res, err := http.DefaultClient.Do(req)
144+
if err != nil {
145+
return fmt.Errorf("failed to request: %w", err)
146+
}
147+
148+
defer res.Body.Close()
149+
150+
if res.StatusCode != http.StatusOK {
151+
return fmt.Errorf("failed to request: %s", res.Status)
152+
}
153+
154+
f, err := zw.Create(filePath)
155+
if err != nil {
156+
return fmt.Errorf("failed to create zip entry: %w", err)
157+
}
158+
159+
if _, err := io.Copy(f, res.Body); err != nil {
160+
return fmt.Errorf("failed to copy: %w", err)
161+
}
162+
163+
return nil
164+
}
165+
166+
func parseList(b []byte) (res [][]string, err error) {
167+
start := 0
168+
for i, c := range b {
169+
if c == '\n' {
170+
r := string(b[start:i])
171+
start = i + 1
172+
173+
s := reSpace.Split(r, -1)
174+
if len(s) <= 3 {
175+
err = fmt.Errorf("invalid line at %d: %s", i, r)
176+
return
177+
}
178+
179+
t := strings.Split(s[3], "/")
180+
if strings.HasPrefix(t[len(t)-1], ".") {
181+
continue
182+
}
183+
184+
if len(t) <= 2 {
185+
err = fmt.Errorf("invalid line at %d: %s", i, r)
186+
return
187+
}
188+
189+
res = append(res, t)
190+
}
191+
}
192+
193+
return
194+
}
195+
196+
var reSpace = regexp.MustCompile(`\s+`)

Diff for: server/tool.go renamed to server/tool/setup-city-items.go

+1-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package main
1+
package tool
22

33
import (
44
"context"
@@ -13,30 +13,6 @@ import (
1313
"github.com/samber/lo"
1414
)
1515

16-
func tool(conf *Config, args []string) {
17-
subommand := args[0]
18-
var err error
19-
20-
switch subommand {
21-
case "setup-city-items":
22-
err = setupCityItems(conf, args[1:])
23-
case "help":
24-
err = help(conf)
25-
default:
26-
err = errors.New("invalid subcommand")
27-
}
28-
29-
if err != nil {
30-
fmt.Println(err)
31-
os.Exit(1)
32-
}
33-
}
34-
35-
func help(*Config) error {
36-
fmt.Println(`Usage: plateauview <command> [arguments] [options] [flags]`)
37-
return nil
38-
}
39-
4016
func setupCityItems(conf *Config, args []string) error {
4117
println("setup-city-items")
4218

Diff for: server/tool/tool.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package tool
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
)
8+
9+
type Config struct {
10+
CMS_BaseURL string
11+
CMS_Token string
12+
}
13+
14+
func Main(conf *Config, args []string) {
15+
subommand := args[0]
16+
var err error
17+
18+
switch subommand {
19+
case "setup-city-items":
20+
err = setupCityItems(conf, args[1:])
21+
case "migrate-v1":
22+
err = migrateV1(conf, args[1:])
23+
case "upload-assets":
24+
err = uploadAssets(conf, args[1:])
25+
case "help":
26+
err = help(conf)
27+
default:
28+
err = errors.New("invalid subcommand")
29+
}
30+
31+
if err != nil {
32+
fmt.Println(err)
33+
os.Exit(1)
34+
}
35+
}
36+
37+
func help(*Config) error {
38+
fmt.Println(`Usage: plateauview <command> [arguments] [options] [flags]`)
39+
return nil
40+
}

Diff for: server/tool/upload-assets.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package tool
2+
3+
import (
4+
"context"
5+
"errors"
6+
"flag"
7+
"fmt"
8+
"os"
9+
"path"
10+
"path/filepath"
11+
12+
cms "github.com/reearth/reearth-cms-api/go"
13+
)
14+
15+
func uploadAssets(conf *Config, args []string) error {
16+
var base, token, pid, target string
17+
18+
flags := flag.NewFlagSet("upload-assets", flag.ExitOnError)
19+
flags.StringVar(&base, "base", conf.CMS_BaseURL, "CMS base URL")
20+
flags.StringVar(&token, "token", conf.CMS_Token, "CMS token")
21+
flags.StringVar(&pid, "project", "", "project ID")
22+
flags.StringVar(&target, "target", "", "target dir path")
23+
24+
if err := flags.Parse(args); err != nil {
25+
return err
26+
}
27+
28+
if pid == "" {
29+
return errors.New("project ID is required")
30+
}
31+
32+
c, err := cms.New(base, token)
33+
if err != nil {
34+
return err
35+
}
36+
37+
files, err := os.ReadDir(target)
38+
if err != nil {
39+
return err
40+
}
41+
42+
ctx := context.Background()
43+
for _, f := range files {
44+
if f.IsDir() {
45+
continue
46+
}
47+
48+
ext := path.Ext(f.Name())
49+
if ext != ".zip" {
50+
continue
51+
}
52+
53+
file, err := os.Open(filepath.Join(target, f.Name()))
54+
if err != nil {
55+
return err
56+
}
57+
58+
fmt.Printf("%s -> ", file.Name())
59+
60+
assetID, err := c.UploadAssetDirectly(ctx, pid, file.Name(), file)
61+
if err != nil {
62+
return err
63+
}
64+
65+
fmt.Printf("%s\n", assetID)
66+
}
67+
68+
return nil
69+
}

Diff for: tools/src/args.rs

-7
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ pub enum Commands {
2323
#[clap(short, long)]
2424
output: Option<PathBuf>,
2525
},
26-
/// PLATEAU VIEW 1.1 のS3内に格納されたユースケースデータのファイルを移行します。
27-
MigrateUC {
28-
#[clap(short, long)]
29-
list_path: PathBuf,
30-
#[clap(short, long)]
31-
output: Option<PathBuf>,
32-
},
3326
}
3427

3528
#[derive(Debug, Clone, ValueEnum)]

0 commit comments

Comments
 (0)