2020-09-03 15:13:19 +00:00
// Vikunja is a to-do list application to facilitate your life.
2021-02-02 20:19:13 +01:00
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
2020-09-03 15:13:19 +00:00
//
// This program is free software: you can redistribute it and/or modify
2020-12-23 16:41:52 +01:00
// it under the terms of the GNU Affero General Public Licensee as published by
2020-09-03 15:13:19 +00:00
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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
2020-12-23 16:41:52 +01:00
// GNU Affero General Public Licensee for more details.
2020-09-03 15:13:19 +00:00
//
2020-12-23 16:41:52 +01:00
// You should have received a copy of the GNU Affero General Public Licensee
2020-09-03 15:13:19 +00:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2022-01-23 12:59:43 +00:00
//go:build mage
2020-09-03 15:13:19 +00:00
// +build mage
package main
import (
"bufio"
"bytes"
"context"
"crypto/sha256"
"fmt"
2021-02-02 22:48:37 +00:00
"github.com/iancoleman/strcase"
2020-09-03 15:13:19 +00:00
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
2020-09-04 10:15:33 +02:00
"time"
2020-12-17 13:44:04 +00:00
"github.com/magefile/mage/mg"
"golang.org/x/sync/errgroup"
"gopkg.in/yaml.v3"
2020-09-03 15:13:19 +00:00
)
const (
PACKAGE = ` code.vikunja.io/api `
DIST = ` dist `
)
var (
Goflags = [ ] string {
"-v" ,
}
Executable = "vikunja"
Ldflags = ""
Tags = ""
VersionNumber = "dev"
2021-02-10 19:56:51 +01:00
Version = "unstable" // This holds the built version, unstable by default, when building from a tag or release branch, their name
2020-09-03 15:13:19 +00:00
BinLocation = ""
2021-02-10 19:56:51 +01:00
PkgVersion = "unstable"
2020-09-03 15:13:19 +00:00
ApiPackages = [ ] string { }
RootPath = ""
GoFiles = [ ] string { }
// Aliases are mage aliases of targets
Aliases = map [ string ] interface { } {
2021-02-07 21:05:09 +00:00
"build" : Build . Build ,
"do-the-swag" : DoTheSwag ,
"check:got-swag" : Check . GotSwag ,
"release:os-package" : Release . OsPackage ,
"dev:make-migration" : Dev . MakeMigration ,
"dev:make-event" : Dev . MakeEvent ,
"dev:make-listener" : Dev . MakeListener ,
"dev:make-notification" : Dev . MakeNotification ,
"generate-docs" : GenerateDocs ,
"check:golangci-fix" : Check . GolangciFix ,
2020-09-03 15:13:19 +00:00
}
)
2021-09-24 20:03:38 +02:00
func runCmdWithOutput ( name string , arg ... string ) ( output [ ] byte , err error ) {
cmd := exec . Command ( name , arg ... )
output , err = cmd . Output ( )
if err != nil {
2022-08-03 17:11:17 +02:00
if ee , is := err . ( * exec . ExitError ) ; is {
return nil , fmt . Errorf ( "error running command: %s, %s" , string ( ee . Stderr ) , err )
}
return nil , fmt . Errorf ( "error running command: %s" , err )
2021-09-24 20:03:38 +02:00
}
return output , nil
}
2020-09-03 15:13:19 +00:00
func setVersion ( ) {
2021-09-24 20:03:38 +02:00
version , err := runCmdWithOutput ( "git" , "describe" , "--tags" , "--always" , "--abbrev=10" )
2020-09-03 15:13:19 +00:00
if err != nil {
fmt . Printf ( "Error getting version: %s\n" , err )
os . Exit ( 1 )
}
VersionNumber = strings . Trim ( string ( version ) , "\n" )
VersionNumber = strings . Replace ( VersionNumber , "-" , "+" , 1 )
VersionNumber = strings . Replace ( VersionNumber , "-g" , "-" , 1 )
if os . Getenv ( "DRONE_TAG" ) != "" {
Version = os . Getenv ( "DRONE_TAG" )
} else if os . Getenv ( "DRONE_BRANCH" ) != "" {
Version = strings . Replace ( os . Getenv ( "DRONE_BRANCH" ) , "release/v" , "" , 1 )
}
2021-02-13 16:32:26 +01:00
if Version == "main" {
Version = "unstable"
}
2020-09-03 15:13:19 +00:00
}
func setBinLocation ( ) {
if os . Getenv ( "DRONE_WORKSPACE" ) != "" {
BinLocation = DIST + ` /binaries/ ` + Executable + ` - ` + Version + ` -linux-amd64 `
} else {
BinLocation = Executable
}
}
func setPkgVersion ( ) {
2021-02-10 19:56:51 +01:00
if Version == "unstable" {
2020-09-03 15:13:19 +00:00
PkgVersion = VersionNumber
}
}
func setExecutable ( ) {
if runtime . GOOS == "windows" {
Executable += ".exe"
}
}
func setApiPackages ( ) {
2021-09-24 20:03:38 +02:00
pkgs , err := runCmdWithOutput ( "go" , "list" , "all" )
2020-09-03 15:13:19 +00:00
if err != nil {
fmt . Printf ( "Error getting packages: %s\n" , err )
os . Exit ( 1 )
}
for _ , p := range strings . Split ( string ( pkgs ) , "\n" ) {
if strings . Contains ( p , "code.vikunja.io/api" ) && ! strings . Contains ( p , "code.vikunja.io/api/pkg/integrations" ) {
ApiPackages = append ( ApiPackages , p )
}
}
}
func setRootPath ( ) {
pwd , err := os . Getwd ( )
if err != nil {
fmt . Printf ( "Error getting pwd: %s\n" , err )
os . Exit ( 1 )
}
if err := os . Setenv ( "VIKUNJA_SERVICE_ROOTPATH" , pwd ) ; err != nil {
fmt . Printf ( "Error setting root path: %s\n" , err )
os . Exit ( 1 )
}
RootPath = pwd
}
func setGoFiles ( ) {
// GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go")
2021-09-24 20:03:38 +02:00
files , err := runCmdWithOutput ( "find" , "." , "-name" , "*.go" , "-type" , "f" , "!" , "-path" , "*/bindata.go" )
2020-09-03 15:13:19 +00:00
if err != nil {
fmt . Printf ( "Error getting go files: %s\n" , err )
os . Exit ( 1 )
}
for _ , f := range strings . Split ( string ( files ) , "\n" ) {
if strings . HasSuffix ( f , ".go" ) {
GoFiles = append ( GoFiles , RootPath + strings . TrimLeft ( f , "." ) )
}
}
}
2020-09-03 22:14:30 +02:00
// Some variables can always get initialized, so we do just that.
2020-09-03 15:13:19 +00:00
func init ( ) {
2020-09-03 22:14:30 +02:00
setExecutable ( )
setRootPath ( )
}
// Some variables have external dependencies (like git) which may not always be available.
func initVars ( ) {
2020-09-03 15:13:19 +00:00
Tags = os . Getenv ( "TAGS" )
2023-04-06 12:11:27 +02:00
if ! strings . Contains ( Tags , "swagger" ) {
Tags += " swagger"
}
2020-09-03 15:13:19 +00:00
setVersion ( )
setBinLocation ( )
setPkgVersion ( )
setGoFiles ( )
Ldflags = ` -X " ` + PACKAGE + ` /pkg/version.Version= ` + VersionNumber + ` " -X "main.Tags= ` + Tags + ` " `
}
func runAndStreamOutput ( cmd string , args ... string ) {
c := exec . Command ( cmd , args ... )
c . Env = os . Environ ( )
c . Dir = RootPath
fmt . Printf ( "%s\n\n" , c . String ( ) )
stdout , _ := c . StdoutPipe ( )
errbuf := bytes . Buffer { }
c . Stderr = & errbuf
2023-04-02 18:55:30 +02:00
err := c . Start ( )
if err != nil {
fmt . Printf ( "Could not start: %s\n" , err )
os . Exit ( 1 )
}
2020-09-03 15:13:19 +00:00
reader := bufio . NewReader ( stdout )
line , err := reader . ReadString ( '\n' )
for err == nil {
fmt . Print ( line )
line , err = reader . ReadString ( '\n' )
}
if err := c . Wait ( ) ; err != nil {
fmt . Printf ( errbuf . String ( ) )
fmt . Printf ( "Error: %s\n" , err )
os . Exit ( 1 )
}
}
// Will check if the tool exists and if not install it from the provided import path
// If any errors occur, it will exit with a status code of 1.
func checkAndInstallGoTool ( tool , importPath string ) {
if err := exec . Command ( tool ) . Run ( ) ; err != nil && strings . Contains ( err . Error ( ) , "executable file not found" ) {
fmt . Printf ( "%s not installed, installing %s...\n" , tool , importPath )
if err := exec . Command ( "go" , "install" , Goflags [ 0 ] , importPath ) . Run ( ) ; err != nil {
fmt . Printf ( "Error installing %s\n" , tool )
os . Exit ( 1 )
}
fmt . Println ( "Installed." )
}
}
// Calculates a hash of a file
func calculateSha256FileHash ( path string ) ( hash string , err error ) {
f , err := os . Open ( path )
if err != nil {
return "" , err
}
defer f . Close ( )
h := sha256 . New ( )
if _ , err := io . Copy ( h , f ) ; err != nil {
return "" , err
}
return fmt . Sprintf ( "%x" , h . Sum ( nil ) ) , nil
}
// Copy the src file to dst. Any existing file will be overwritten and will not
// copy file attributes.
func copyFile ( src , dst string ) error {
in , err := os . Open ( src )
if err != nil {
return err
}
defer in . Close ( )
out , err := os . Create ( dst )
if err != nil {
return err
}
defer out . Close ( )
_ , err = io . Copy ( out , in )
if err != nil {
return err
}
si , err := os . Stat ( src )
if err != nil {
return err
}
if err := os . Chmod ( dst , si . Mode ( ) ) ; err != nil {
return err
}
return out . Close ( )
}
2020-09-03 20:42:26 +02:00
// os.Rename has issues with moving files between docker volumes.
// Because of this limitaion, it fails in drone.
// Source: https://gist.github.com/var23rav/23ae5d0d4d830aff886c3c970b8f6c6b
2020-09-04 14:00:54 +02:00
func moveFile ( src , dst string ) error {
inputFile , err := os . Open ( src )
defer inputFile . Close ( )
2020-09-03 20:42:26 +02:00
if err != nil {
return fmt . Errorf ( "couldn't open source file: %s" , err )
}
2020-09-04 14:00:54 +02:00
outputFile , err := os . Create ( dst )
defer outputFile . Close ( )
2020-09-03 20:42:26 +02:00
if err != nil {
return fmt . Errorf ( "couldn't open dest file: %s" , err )
}
2020-09-04 14:00:54 +02:00
2020-09-03 20:42:26 +02:00
_ , err = io . Copy ( outputFile , inputFile )
if err != nil {
return fmt . Errorf ( "writing to output file failed: %s" , err )
}
2020-09-04 14:00:54 +02:00
// Make sure to copy copy the permissions of the original file as well
si , err := os . Stat ( src )
if err != nil {
return err
}
if err := os . Chmod ( dst , si . Mode ( ) ) ; err != nil {
return err
}
2020-09-03 20:42:26 +02:00
// The copy was successful, so now delete the original file
2020-09-04 14:00:54 +02:00
err = os . Remove ( src )
2020-09-03 20:42:26 +02:00
if err != nil {
return fmt . Errorf ( "failed removing original file: %s" , err )
}
return nil
}
2021-02-02 22:48:37 +00:00
func appendToFile ( filename , content string ) error {
f , err := os . OpenFile ( filename , os . O_APPEND | os . O_WRONLY | os . O_CREATE , 0600 )
if err != nil {
return err
}
defer f . Close ( )
_ , err = f . WriteString ( content )
return err
}
const InfoColor = "\033[1;32m%s\033[0m"
func printSuccess ( text string , args ... interface { } ) {
text = fmt . Sprintf ( text , args ... )
fmt . Printf ( InfoColor + "\n" , text )
}
2020-09-03 15:13:19 +00:00
// Formats the code using go fmt
func Fmt ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
args := append ( [ ] string { "-s" , "-w" } , GoFiles ... )
runAndStreamOutput ( "gofmt" , args ... )
}
2023-04-02 18:55:30 +02:00
const swaggerDocsFolderLocation = ` ./pkg/swagger/ `
2020-09-03 15:13:19 +00:00
// Generates the swagger docs from the code annotations
func DoTheSwag ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2023-04-02 18:55:30 +02:00
if _ , err := os . Stat ( swaggerDocsFolderLocation + "swagger.json" ) ; err == nil {
fmt . Println ( "Swagger docs already generated, not generating. Remove the files in " + swaggerDocsFolderLocation + " and run this command again to regenerate them." )
2023-04-02 16:52:54 +02:00
return
}
2020-09-03 15:13:19 +00:00
checkAndInstallGoTool ( "swag" , "github.com/swaggo/swag/cmd/swag" )
runAndStreamOutput ( "swag" , "init" , "-g" , "./pkg/routes/routes.go" , "--parseDependency" , "-d" , RootPath , "-o" , RootPath + "/pkg/swagger" )
}
type Test mg . Namespace
// Runs all tests except integration tests
func ( Test ) Unit ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2021-10-02 15:40:56 +02:00
setApiPackages ( )
2020-09-03 15:13:19 +00:00
// We run everything sequentially and not in parallel to prevent issues with real test databases
2022-08-02 22:49:48 +02:00
args := append ( [ ] string { "test" , Goflags [ 0 ] , "-p" , "1" , "-coverprofile" , "cover.out" , "-timeout" , "45m" } , ApiPackages ... )
2020-09-03 15:13:19 +00:00
runAndStreamOutput ( "go" , args ... )
}
// Runs the tests and builds the coverage html file from coverage output
func ( Test ) Coverage ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
mg . Deps ( Test . Unit )
runAndStreamOutput ( "go" , "tool" , "cover" , "-html=cover.out" , "-o" , "cover.html" )
}
// Runs the integration tests
func ( Test ) Integration ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
// We run everything sequentially and not in parallel to prevent issues with real test databases
2022-08-02 22:49:48 +02:00
runAndStreamOutput ( "go" , "test" , Goflags [ 0 ] , "-p" , "1" , "-timeout" , "45m" , PACKAGE + "/pkg/integrations" )
2020-09-03 15:13:19 +00:00
}
type Check mg . Namespace
// Checks if the swagger docs need to be re-generated from the code annotations
func ( Check ) GotSwag ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
// The check is pretty cheaply done: We take the hash of the swagger.json file, generate the docs,
// hash the file again and compare the two hashes to see if anything changed. If that's the case,
// regenerating the docs is necessary.
// swag is not capable of just outputting the generated docs to stdout, therefore we need to do it this way.
// Another drawback of this is obviously it will only work once - we're not resetting the newly generated
// docs after the check. This behaviour is good enough for ci though.
oldHash , err := calculateSha256FileHash ( RootPath + "/pkg/swagger/swagger.json" )
if err != nil {
fmt . Printf ( "Error getting old hash of the swagger docs: %s" , err )
os . Exit ( 1 )
}
DoTheSwag ( )
newHash , err := calculateSha256FileHash ( RootPath + "/pkg/swagger/swagger.json" )
if err != nil {
fmt . Printf ( "Error getting new hash of the swagger docs: %s" , err )
os . Exit ( 1 )
}
if oldHash != newHash {
fmt . Println ( "Swagger docs are not up to date." )
fmt . Println ( "Please run 'mage do-the-swag' and commit the result." )
os . Exit ( 1 )
}
}
2020-10-11 20:10:03 +00:00
func checkGolangCiLintInstalled ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-10-11 20:10:03 +00:00
if err := exec . Command ( "golangci-lint" ) . Run ( ) ; err != nil && strings . Contains ( err . Error ( ) , "executable file not found" ) {
fmt . Println ( "Please manually install golangci-lint by running" )
2023-06-05 18:07:12 +02:00
fmt . Println ( "curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.2" )
2020-09-03 15:13:19 +00:00
os . Exit ( 1 )
}
}
2020-10-11 20:10:03 +00:00
func ( Check ) Golangci ( ) {
checkGolangCiLintInstalled ( )
runAndStreamOutput ( "golangci-lint" , "run" )
}
func ( Check ) GolangciFix ( ) {
checkGolangCiLintInstalled ( )
runAndStreamOutput ( "golangci-lint" , "run" , "--fix" )
2020-09-03 15:13:19 +00:00
}
2021-03-28 17:24:56 +02:00
// Runs golangci and the swagger test in parralel
2020-09-03 15:13:19 +00:00
func ( Check ) All ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
mg . Deps (
2020-10-11 20:10:03 +00:00
Check . Golangci ,
2020-09-03 15:13:19 +00:00
Check . GotSwag ,
)
}
type Build mg . Namespace
// Cleans all build, executable and bindata files
func ( Build ) Clean ( ) error {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2020-09-03 15:13:19 +00:00
if err := exec . Command ( "go" , "clean" , "./..." ) . Run ( ) ; err != nil {
return err
}
if err := os . Remove ( Executable ) ; err != nil && ! os . IsNotExist ( err ) {
return err
}
if err := os . RemoveAll ( DIST ) ; err != nil && ! os . IsNotExist ( err ) {
return err
}
if err := os . RemoveAll ( BinLocation ) ; err != nil && ! os . IsNotExist ( err ) {
return err
}
2023-04-02 18:55:30 +02:00
if err := os . RemoveAll ( swaggerDocsFolderLocation ) ; err != nil && ! os . IsNotExist ( err ) {
return err
}
2020-09-03 15:13:19 +00:00
return nil
}
// Builds a vikunja binary, ready to run
func ( Build ) Build ( ) {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2023-04-02 16:52:54 +02:00
mg . Deps ( DoTheSwag )
2020-09-03 15:13:19 +00:00
runAndStreamOutput ( "go" , "build" , Goflags [ 0 ] , "-tags" , Tags , "-ldflags" , "-s -w " + Ldflags , "-o" , Executable )
}
type Release mg . Namespace
// Runs all steps in the right order to create release packages for various platforms
func ( Release ) Release ( ctx context . Context ) error {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2021-02-07 21:05:09 +00:00
mg . Deps ( Release . Dirs )
2023-04-02 16:52:54 +02:00
mg . Deps ( DoTheSwag )
2020-09-03 15:13:19 +00:00
// Run compiling in parallel to speed it up
errs , _ := errgroup . WithContext ( ctx )
errs . Go ( ( Release { } ) . Windows )
errs . Go ( ( Release { } ) . Linux )
errs . Go ( ( Release { } ) . Darwin )
if err := errs . Wait ( ) ; err != nil {
return err
}
if err := ( Release { } ) . Compress ( ctx ) ; err != nil {
return err
}
if err := ( Release { } ) . Copy ( ) ; err != nil {
return err
}
if err := ( Release { } ) . Check ( ) ; err != nil {
return err
}
if err := ( Release { } ) . OsPackage ( ) ; err != nil {
return err
}
if err := ( Release { } ) . Zip ( ) ; err != nil {
return err
}
return nil
}
// Creates all directories needed to release vikunja
func ( Release ) Dirs ( ) error {
for _ , d := range [ ] string { "binaries" , "release" , "zip" } {
if err := os . MkdirAll ( RootPath + "/" + DIST + "/" + d , 0755 ) ; err != nil {
return err
}
}
return nil
}
func runXgo ( targets string ) error {
2020-09-03 22:14:30 +02:00
mg . Deps ( initVars )
2023-04-02 16:52:54 +02:00
mg . Deps ( DoTheSwag )
2020-09-03 15:13:19 +00:00
checkAndInstallGoTool ( "xgo" , "src.techknowlogick.com/xgo" )
2020-09-03 21:22:41 +02:00
extraLdflags := ` -linkmode external -extldflags "-static" `
// See https://github.com/techknowlogick/xgo/issues/79
if strings . HasPrefix ( targets , "darwin" ) {
extraLdflags = ""
}
2020-09-03 15:13:19 +00:00
runAndStreamOutput ( "xgo" ,
"-dest" , RootPath + "/" + DIST + "/binaries" ,
"-tags" , "netgo " + Tags ,
2020-09-03 21:22:41 +02:00
"-ldflags" , extraLdflags + Ldflags ,
2020-09-03 15:13:19 +00:00
"-targets" , targets ,
"-out" , Executable + "-" + Version ,
RootPath )
if os . Getenv ( "DRONE_WORKSPACE" ) != "" {
return filepath . Walk ( "/build/" , func ( path string , info os . FileInfo , err error ) error {
2020-09-03 18:08:57 +02:00
// Skip directories
if info . IsDir ( ) {
return nil
}
2020-09-03 20:42:26 +02:00
return moveFile ( path , RootPath + "/" + DIST + "/binaries/" + info . Name ( ) )
2020-09-03 15:13:19 +00:00
} )
}
return nil
}
// Builds binaries for windows
func ( Release ) Windows ( ) error {
return runXgo ( "windows/*" )
}
// Builds binaries for linux
func ( Release ) Linux ( ) error {
return runXgo ( "linux/*" )
}
// Builds binaries for darwin
func ( Release ) Darwin ( ) error {
2021-02-18 21:35:45 +01:00
return runXgo ( "darwin-10.15/*" )
2020-09-03 15:13:19 +00:00
}
2022-11-12 14:29:57 +01:00
func ( Release ) Xgo ( target string ) error {
parts := strings . Split ( target , "/" )
if len ( parts ) < 2 {
return fmt . Errorf ( "invalid target" )
}
variant := ""
if len ( parts ) > 2 && parts [ 2 ] != "" {
variant = "-" + strings . ReplaceAll ( parts [ 2 ] , "v" , "" )
}
return runXgo ( parts [ 0 ] + "/" + parts [ 1 ] + variant )
}
2020-09-03 15:13:19 +00:00
// Compresses the built binaries in dist/binaries/ to reduce their filesize
func ( Release ) Compress ( ctx context . Context ) error {
// $(foreach file,$(filter-out $(wildcard $(wildcard $(DIST)/binaries/$(EXECUTABLE)-*mips*)),$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*)), upx -9 $(file);)
errs , _ := errgroup . WithContext ( ctx )
filepath . Walk ( RootPath + "/" + DIST + "/binaries/" , func ( path string , info os . FileInfo , err error ) error {
// Only executable files
if ! strings . Contains ( info . Name ( ) , Executable ) {
return nil
}
// No mips or s390x for you today
2022-09-07 16:38:43 +02:00
if strings . Contains ( info . Name ( ) , "mips" ) ||
strings . Contains ( info . Name ( ) , "s390x" ) ||
strings . Contains ( info . Name ( ) , "riscv64" ) { // not supported by upx
2020-09-03 15:13:19 +00:00
return nil
}
// Runs compressing in parallel since upx is single-threaded
errs . Go ( func ( ) error {
2020-09-03 22:45:04 +02:00
runAndStreamOutput ( "chmod" , "+x" , path ) // Make sure all binaries are executable. Sometimes the CI does weired things and they're not.
2020-09-03 15:13:19 +00:00
runAndStreamOutput ( "upx" , "-9" , path )
return nil
} )
return nil
} )
return errs . Wait ( )
}
// Copies all built binaries to dist/release/ in preparation for creating the os packages
func ( Release ) Copy ( ) error {
return filepath . Walk ( RootPath + "/" + DIST + "/binaries/" , func ( path string , info os . FileInfo , err error ) error {
// Only executable files
if ! strings . Contains ( info . Name ( ) , Executable ) {
return nil
}
return copyFile ( path , RootPath + "/" + DIST + "/release/" + info . Name ( ) )
} )
}
// Creates sha256 checksum files for each binary in dist/release/
func ( Release ) Check ( ) error {
p := RootPath + "/" + DIST + "/release/"
return filepath . Walk ( p , func ( path string , info os . FileInfo , err error ) error {
if info . IsDir ( ) {
return nil
}
f , err := os . Create ( p + info . Name ( ) + ".sha256" )
if err != nil {
return err
}
hash , err := calculateSha256FileHash ( path )
if err != nil {
return err
}
_ , err = f . WriteString ( hash + " " + info . Name ( ) )
if err != nil {
return err
}
return f . Close ( )
} )
}
// Creates a folder for each
func ( Release ) OsPackage ( ) error {
p := RootPath + "/" + DIST + "/release/"
// We first put all files in a map to then iterate over it since the walk function would otherwise also iterate
// over the newly created files, creating some kind of endless loop.
bins := make ( map [ string ] os . FileInfo )
if err := filepath . Walk ( p , func ( path string , info os . FileInfo , err error ) error {
if strings . Contains ( info . Name ( ) , ".sha256" ) || info . IsDir ( ) {
return nil
}
bins [ path ] = info
return nil
} ) ; err != nil {
return err
}
for path , info := range bins {
folder := p + info . Name ( ) + "-full/"
if err := os . Mkdir ( folder , 0755 ) ; err != nil {
return err
}
2020-09-03 20:42:26 +02:00
if err := moveFile ( p + info . Name ( ) + ".sha256" , folder + info . Name ( ) + ".sha256" ) ; err != nil {
2020-09-03 15:13:19 +00:00
return err
}
2020-09-03 20:42:26 +02:00
if err := moveFile ( path , folder + info . Name ( ) ) ; err != nil {
2020-09-03 15:13:19 +00:00
return err
}
if err := copyFile ( RootPath + "/config.yml.sample" , folder + "config.yml.sample" ) ; err != nil {
return err
}
if err := copyFile ( RootPath + "/LICENSE" , folder + "LICENSE" ) ; err != nil {
return err
}
}
return nil
}
// Creates a zip file from all os-package folders in dist/release
func ( Release ) Zip ( ) error {
p := RootPath + "/" + DIST + "/release/"
if err := filepath . Walk ( p , func ( path string , info os . FileInfo , err error ) error {
if ! info . IsDir ( ) || info . Name ( ) == "release" {
return nil
}
fmt . Printf ( "Zipping %s...\n" , info . Name ( ) )
2022-10-02 16:29:10 +02:00
c := exec . Command ( "zip" , "-r" , RootPath + "/" + DIST + "/zip/" + info . Name ( ) + ".zip" , "." , "-i" , "*" )
2020-09-03 15:13:19 +00:00
c . Dir = path
out , err := c . Output ( )
fmt . Print ( string ( out ) )
return err
} ) ; err != nil {
return err
}
return nil
}
// Creates a debian repo structure
func ( Release ) Reprepro ( ) {
2020-10-18 11:41:27 +00:00
mg . Deps ( setVersion , setBinLocation )
2020-12-18 23:33:23 +01:00
runAndStreamOutput ( "reprepro_expect" , "debian" , "includedeb" , "buster" , RootPath + "/" + DIST + "/os-packages/" + Executable + "_" + strings . ReplaceAll ( VersionNumber , "v0" , "0" ) + "_amd64.deb" )
2020-10-18 11:41:27 +00:00
}
// Creates deb, rpm and apk packages
func ( Release ) Packages ( ) error {
mg . Deps ( initVars )
2020-10-19 07:58:24 +02:00
var err error
binpath := "nfpm"
err = exec . Command ( binpath ) . Run ( )
if err != nil && strings . Contains ( err . Error ( ) , "executable file not found" ) {
2022-12-19 15:36:39 +01:00
binpath = "/usr/bin/nfpm"
2020-10-19 07:58:24 +02:00
err = exec . Command ( binpath ) . Run ( )
}
if err != nil && strings . Contains ( err . Error ( ) , "executable file not found" ) {
2020-10-18 11:41:27 +00:00
fmt . Println ( "Please manually install nfpm by running" )
fmt . Println ( "curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin" )
os . Exit ( 1 )
}
2022-12-19 15:36:39 +01:00
// Because nfpm does not support templating, we replace the values in the config file and restore it after running
2020-10-18 11:41:27 +00:00
nfpmConfigPath := RootPath + "/nfpm.yaml"
2022-10-01 15:05:12 +00:00
nfpmconfig , err := os . ReadFile ( nfpmConfigPath )
2020-10-18 11:41:27 +00:00
if err != nil {
return err
}
fixedConfig := strings . ReplaceAll ( string ( nfpmconfig ) , "<version>" , VersionNumber )
fixedConfig = strings . ReplaceAll ( fixedConfig , "<binlocation>" , BinLocation )
2022-10-01 15:05:12 +00:00
if err := os . WriteFile ( nfpmConfigPath , [ ] byte ( fixedConfig ) , 0 ) ; err != nil {
2020-10-18 11:41:27 +00:00
return err
}
releasePath := RootPath + "/" + DIST + "/os-packages/"
if err := os . MkdirAll ( releasePath , 0755 ) ; err != nil {
return err
}
2020-10-19 07:58:24 +02:00
runAndStreamOutput ( binpath , "pkg" , "--packager" , "deb" , "--target" , releasePath )
runAndStreamOutput ( binpath , "pkg" , "--packager" , "rpm" , "--target" , releasePath )
runAndStreamOutput ( binpath , "pkg" , "--packager" , "apk" , "--target" , releasePath )
2020-10-18 11:41:27 +00:00
2022-10-01 15:05:12 +00:00
return os . WriteFile ( nfpmConfigPath , nfpmconfig , 0 )
2020-09-03 15:13:19 +00:00
}
2020-09-04 10:15:33 +02:00
type Dev mg . Namespace
// Creates a new bare db migration skeleton in pkg/migration with the current date
2021-02-02 22:48:37 +00:00
func ( Dev ) MakeMigration ( ) error {
2020-09-04 10:15:33 +02:00
reader := bufio . NewReader ( os . Stdin )
fmt . Print ( "Enter the name of the struct: " )
str , _ := reader . ReadString ( '\n' )
str = strings . Trim ( str , "\n" )
date := time . Now ( ) . Format ( "20060102150405" )
migration := ` // Vikunja is a to-do list application to facilitate your life.
2021-02-02 20:19:13 +01:00
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
2020-09-04 10:15:33 +02:00
//
// This program is free software: you can redistribute it and/or modify
2020-12-23 16:41:52 +01:00
// it under the terms of the GNU Affero General Public Licensee as published by
2020-09-04 10:15:33 +02:00
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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
2020-12-23 16:41:52 +01:00
// GNU Affero General Public Licensee for more details.
2020-09-04 10:15:33 +02:00
//
2020-12-23 16:41:52 +01:00
// You should have received a copy of the GNU Affero General Public Licensee
2020-09-04 10:15:33 +02:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration