proton-bridge/utils/versioner/main.go

190 lines
4.2 KiB
Go

// Copyright (c) 2024 Proton AG
//
// This file is part of Proton Mail Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/Masterminds/semver/v3"
"github.com/ProtonMail/proton-bridge/v3/internal/updater"
"github.com/go-resty/resty/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
type versionInfo struct {
updater.VersionInfo
Commit string
}
func main() {
if err := createApp().Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
func createApp() *cli.App {
app := cli.NewApp()
app.Name = "versioner"
app.Usage = "Create and update version files"
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "app",
Usage: "The app (bridge, importExport)",
Required: true,
},
&cli.StringFlag{
Name: "platform",
Usage: "The platform (windows, darwin, linux)",
Required: true,
},
}
app.Commands = []*cli.Command{{
Name: "update",
Action: update,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "channel",
Usage: "The update channel (live/beta/...)",
Required: true,
},
&cli.StringFlag{
Name: "version",
Usage: "The version of the app",
},
&cli.StringFlag{
Name: "min-auto",
Usage: "The minimum version of the app that can autoupdate to this version",
},
&cli.StringFlag{
Name: "package",
Usage: "The package file",
},
&cli.StringSliceFlag{
Name: "installer",
Usage: "An installer that can be used to manually install the app (can be specified multiple times)",
},
&cli.StringFlag{
Name: "landing-page",
Usage: "The landing page",
},
&cli.StringFlag{
Name: "release-notes-page",
Usage: "The release notes page",
},
&cli.Float64Flag{
Name: "rollout",
Usage: "What proportion of users should receive this update",
},
&cli.StringFlag{
Name: "commit",
Usage: "What commit produced this update",
},
},
}, {
Name: "dump",
Action: dump,
}}
return app
}
func update(c *cli.Context) error {
versions := fetch(c.String("app"), c.String("platform"))
version := versions[c.String("channel")]
if c.IsSet("version") {
version.Version = semver.MustParse(c.String("version"))
}
if c.IsSet("min-auto") {
version.MinAuto = semver.MustParse(c.String("min-auto"))
}
if c.IsSet("package") {
version.Package = c.String("package")
}
if c.IsSet("installer") {
version.Installers = c.StringSlice("installer")
}
if c.IsSet("landing-page") {
version.LandingPage = c.String("landing-page")
}
if c.IsSet("release-notes-page") {
version.ReleaseNotesPage = c.String("release-notes-page")
}
if c.IsSet("rollout") {
version.RolloutProportion = c.Float64("rollout")
}
if c.IsSet("commit") {
version.Commit = c.String("commit")
}
versions[c.String("channel")] = version
return write(c.App.Writer, versions)
}
func dump(c *cli.Context) error {
return write(c.App.Writer, fetch(c.String("app"), c.String("platform")))
}
func fetch(app, platform string) map[string]versionInfo {
url := fmt.Sprintf(
"%v/%v/version_%v.json",
updater.Host, app, platform,
)
res, err := resty.New().R().Get(url)
if err != nil {
logrus.WithError(err).Error("Fetch failed.")
return make(map[string]versionInfo)
}
var versionMap map[string]versionInfo
if err := json.Unmarshal(res.Body(), &versionMap); err != nil {
logrus.WithError(err).Error("Unmarshal failed.")
return make(map[string]versionInfo)
}
return versionMap
}
func write(w io.Writer, versions map[string]versionInfo) error {
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(versions)
}