Adding command line options

This commit is contained in:
OLUWADAMILOLA OKUSANYA 2023-06-30 15:06:46 -04:00
parent e3e81130ba
commit cb52ddab05
16 changed files with 751 additions and 274 deletions

26
cmd/gosimplenpm/conf.go Normal file
View File

@ -0,0 +1,26 @@
package gosimplenpm
import (
"fmt"
"gosimplenpm/config"
"os"
"github.com/spf13/cobra"
)
var configCmd = &cobra.Command{
Use: "config",
Aliases: []string{"conf"},
Short: "Display the config file",
Run: func(_ *cobra.Command, _ []string) {
err := config.PrintConfigFile()
if err != nil {
fmt.Printf("Error printing config: %+v\n", err)
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(configCmd)
}

83
cmd/gosimplenpm/root.go Normal file
View File

@ -0,0 +1,83 @@
package gosimplenpm
import (
"fmt"
"gosimplenpm/config"
"gosimplenpm/handler"
"os"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "gosimplenpm",
Short: "Gosimplenpm is an implementation of npm registry server",
Long: `Gosimplenpm is an implemenation of npm registry server.
It creates the repository to host all your private npm repos. It can
serve the npm packages offline.
Documentation about the npm private registry:
https://docs.npmjs.com/packages-and-modules
`,
Run: func(_ *cobra.Command, _ []string) {
err := config.VerifyConfig()
if err != nil {
fmt.Printf("Error verifying config: %+v\n", err)
os.Exit(1)
}
var cfg config.Config
err = config.LoadOrCreateConfig(&cfg)
if err != nil {
fmt.Printf("Error loading config: %+v\n", err)
os.Exit(1)
}
lvl, err := logrus.ParseLevel(cfg.LogLevel)
if err != nil {
fmt.Printf("%+v", err)
os.Exit(1)
}
log := &logrus.Logger{
Out: os.Stdout,
Level: lvl,
Formatter: &logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2009-01-02 15:15:15",
},
}
app := &handler.Application{
Conf: cfg,
Logger: log,
}
fmt.Println("\n Server is starting....")
err = app.Start()
fmt.Println("Why!")
if err != nil {
fmt.Printf("Server start up error: %+v\n", err)
os.Exit(1)
}
},
}
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.CompletionOptions.HiddenDefaultCmd = true
// hide help command
rootCmd.SetHelpCommand(&cobra.Command{Hidden: true})
// hide help flag
rootCmd.PersistentFlags().BoolP("help", "h", false, "This help")
rootCmd.PersistentFlags().Lookup("help").Hidden = true
// TODO: get some variables from flags
rootCmd.Flags().StringVarP(&config.HTTPListen, "listen", "l", config.HTTPListen, "HTTP bind interface and port for server")
_ = rootCmd.MarkFlagRequired("listen")
rootCmd.Flags().BoolVarP(&config.CanLog, "verbose", "v", config.CanLog, "Logging level for server")
rootCmd.Flags().StringVar(&config.NpmRepoDir, "repodir", config.NpmRepoDir, "Repo dir to house published packages")
}

View File

@ -1,36 +0,0 @@
package main
import (
"gosimplenpm/cmd/npmregserver"
"gosimplenpm/config"
"net/http"
"os"
"github.com/sirupsen/logrus"
)
func main() {
log := &logrus.Logger{
Out: os.Stdout,
Level: logrus.DebugLevel,
Formatter: &logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2009-01-02 15:15:15",
},
}
var cfg config.Config
err := config.LoadConfiguration("userdata/config.json", &cfg)
if err != nil {
log.Fatalf("Config is not loaded: %+v\n", err)
}
app := &npmregserver.Application{
Conf: cfg,
Logger: log,
}
log.Infoln("Starting server on port 4000")
err = http.ListenAndServe(":4000", app.Routes())
log.Fatal(err)
}

View File

@ -1,36 +0,0 @@
package npmregserver
import (
"gosimplenpm/config"
"gosimplenpm/handler"
"gosimplenpm/middlewares"
"net/http"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
)
type Application struct {
Logger *logrus.Logger
Conf config.Config
}
func (app *Application) Routes() *mux.Router {
// Need to use UseEncodedPath as shown here https://github.com/gorilla/mux/blob/master/mux.go#L269
m := mux.NewRouter().StrictSlash(true).UseEncodedPath()
m.Use(middlewares.LogMiddleware(app.Logger))
// main handler
m.HandleFunc("/{name}", handler.Get).Methods("GET")
m.HandleFunc("/{name}", middlewares.AuthMiddleware(app.Conf)(handler.Publish)).Methods("PUT")
// tar handlers
m.HandleFunc("/{name}/-/{tar}", handler.Tar).Methods("GET")
// tag handlers
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(handler.DistTagDelete(app.Logger))).Methods("DELETE")
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(handler.DistTagPut(app.Logger))).Methods("PUT")
m.HandleFunc("/-/package/{name}/dist-tags", handler.DistTagGet(app.Logger)).Methods("GET")
m.NotFoundHandler = http.HandlerFunc(handler.NotFound)
return m
}

View File

@ -1,36 +1,316 @@
package config package config
import ( import (
"bufio"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"net"
"os" "os"
"path/filepath" "path"
"golang.org/x/crypto/bcrypt"
)
var (
// File to store the app configuration, like username, password, token, repo dir, logging level
ConfigFilePath string
// Repo dir
NpmRepoDir string
// HTTPListen
HTTPListen string
// Set Verbose Logging
CanLog bool
// Logging Level
LoggingLvl string
// Username
RegUser string
// Password
RegPwd string
) )
type Config struct { type Config struct {
Token string `json:"token"` Token string `json:"token"`
RepoDir string `json:"repoDir"`
IpAddress string `json:"ipAddress"`
LogLevel string `json:"logLevel"`
} }
func LoadConfiguration(file string, config *Config) error { func checkIfCorrectIPPort(s string) bool {
filePath, err := filepath.Abs(file) host, port, _ := net.SplitHostPort(s)
if host == "" || port == "" {
return false
}
if net.ParseIP(host) != nil {
return true
}
_, err := net.ResolveIPAddr("ip", host)
return err == nil
}
func VerifyConfig() error {
if !checkIfCorrectIPPort(HTTPListen) {
return errors.New("ip address should be in the format of <ip>:<port>")
}
// Check if config file exists
dirname, err := os.UserHomeDir()
if err != nil { if err != nil {
fmt.Printf("File repo not found: +%v\n", err)
return err return err
} }
configFile, err := os.Open(filePath) configDirPath, err := checkOrCreateConfigDir(dirname, true)
// From https://stackoverflow/a/76287159 if err != nil {
defer func() { return err
err = errors.Join(err, configFile.Close()) }
ConfigFilePath = path.Join(configDirPath, "config.json")
if NpmRepoDir == "" {
NpmRepoDir = path.Join(dirname, ".gosimplenpm", "registry")
err := checkOrCreateRepoDir(NpmRepoDir)
if err != nil { if err != nil {
fmt.Printf("File cannot be closed: +%v\n", err) return err
}
} else if NpmRepoDir != "" {
err := checkOrCreateRepoDir(NpmRepoDir)
if err != nil {
return err
} }
}()
if err != nil {
fmt.Printf("File cannot be opened: +%v\n", err)
return err
} }
json.NewDecoder(configFile).Decode(config)
fmt.Println("Json loaded") if CanLog {
LoggingLvl = "DEBUG"
fmt.Println("\n Enabled debug logging")
} else {
LoggingLvl = "INFO"
}
return nil
}
func checkOrCreateConfigDir(fp string, canCreate bool) (string, error) {
configDirPath := path.Join(fp, ".gosimplenpm", "config")
ok := isDir(configDirPath)
if !ok && canCreate {
err := os.MkdirAll(configDirPath, os.ModePerm)
if err != nil {
return "", err
}
}
if !ok && !canCreate {
return "", nil
}
return configDirPath, nil
}
func checkOrCreateRepoDir(repoDirPath string) error {
ok := isDir(repoDirPath)
if !ok {
err := os.MkdirAll(repoDirPath, os.ModePerm)
if err != nil {
return err
}
}
return nil
}
func createConfig(cfg *Config, recreate bool) error {
var scanner *bufio.Scanner
if recreate {
fmt.Println("\nNew config variables. Saving...")
} else {
fmt.Println("\nConfig file is not found. Creating...")
}
configFile, err := os.Create(ConfigFilePath)
if err != nil {
return err
}
defer configFile.Close()
cfg.IpAddress = HTTPListen
cfg.LogLevel = LoggingLvl
// Get username
if cfg.Token == "" {
fmt.Println("Enter your username: ")
scanner = bufio.NewScanner(os.Stdin)
scanner.Scan()
err = scanner.Err()
if err != nil {
return err
}
RegUser = scanner.Text()
fmt.Println("Enter your password: ")
scanner = bufio.NewScanner(os.Stdin)
scanner.Scan()
err = scanner.Err()
if err != nil {
return err
}
RegPwd = scanner.Text()
token, err := generateAuthToken()
if err != nil {
return err
}
cfg.Token = token
}
fmt.Printf("The npm authToken is %s.\n", cfg.Token)
err = json.NewEncoder(configFile).Encode(cfg)
if err != nil {
return err
}
return nil
}
func loadConfig(cfg *Config) error {
configFile, err := os.Open(ConfigFilePath)
if err != nil {
return err
}
defer configFile.Close()
err = json.NewDecoder(configFile).Decode(cfg)
if err != nil {
return err
}
return nil
}
func LoadOrCreateConfig(cfg *Config) error {
var err error
ok := isFile(ConfigFilePath)
// If file is not found
if !ok {
err = createConfig(cfg, false)
if err != nil {
return err
}
}
if ok {
// File is found
err = loadConfig(cfg)
if err != nil {
return err
}
if cfg.Token == "" || cfg.IpAddress != HTTPListen || cfg.LogLevel != LoggingLvl || cfg.RepoDir != NpmRepoDir {
// recreate the config file
err = createConfig(cfg, true)
if err != nil {
return err
}
}
}
return err
}
func isFile(fp string) bool {
info, err := os.Stat(fp)
if os.IsNotExist(err) || !info.Mode().IsRegular() {
return false
}
return true
}
func isDir(fp string) bool {
info, err := os.Stat(fp)
if os.IsNotExist(err) || !info.IsDir() {
return false
}
return true
}
// Hash password
func hashPassword(password string) (string, error) {
// Convert password string to byte slice
var passwordBytes = []byte(password)
// Hash password with Bcrypt's min cost
hashedPasswordBytes, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.MinCost)
return string(hashedPasswordBytes), err
}
// Check if two passwords match using Bcrypt's CompareHashAndPassword
// which return nil on success and an error on failure.
// func doPasswordsMatch(hashedPassword, currPassword string) bool {
// err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(currPassword))
// return err == nil
// }
func generateAuthToken() (string, error) {
hashed, err := hashPassword(RegPwd)
if err != nil {
return "", err
}
token := fmt.Sprintf("%s::%s", RegUser, hashed)
return token, nil
}
func PrintConfigFile() error {
// Check if config file exists
dirname, err := os.UserHomeDir()
if err != nil {
return err
}
configDirPath, err := checkOrCreateConfigDir(dirname, false)
if err != nil {
return err
}
if configDirPath == "" {
return errors.New("config dir is not found")
}
ConfigFilePath = path.Join(configDirPath, "config.json")
ok := isFile(ConfigFilePath)
if !ok {
return errors.New("config file is not found")
}
configFile, err := os.Open(ConfigFilePath)
if err != nil {
return err
}
defer configFile.Close()
b, err := io.ReadAll(configFile)
if err != nil {
return err
}
var result map[string]interface{}
err = json.Unmarshal([]byte(b), &result)
if err != nil {
return err
}
// Pretty-print the result
marshaled, err := json.MarshalIndent(result, "", " ")
if err != nil {
return err
}
fmt.Printf("Printing config located at %s: \n %s\n", ConfigFilePath, (marshaled))
return nil return nil
} }

10
go.mod
View File

@ -5,9 +5,13 @@ go 1.20
require ( require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
golang.org/x/crypto v0.10.0
golang.org/x/mod v0.11.0 golang.org/x/mod v0.11.0
) )
require golang.org/x/sys v0.9.0 // indirect require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
// replace gosimplenpm/handler => ./handler github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.9.0 // indirect
)

13
go.sum
View File

@ -1,20 +1,31 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

48
handler/app.go Normal file
View File

@ -0,0 +1,48 @@
package handler
import (
"gosimplenpm/config"
"gosimplenpm/middlewares"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
)
type Application struct {
Logger *logrus.Logger
Conf config.Config
Mux *mux.Router
}
func (app *Application) Routes() {
// Need to use UseEncodedPath as shown here https://github.com/gorilla/mux/blob/master/mux.go#L269
m := mux.NewRouter().StrictSlash(true).UseEncodedPath()
m.Use(middlewares.LogMiddleware(app.Logger))
// main handler
m.HandleFunc("/{name}", GetPackage(app.Logger, app.Conf)).Methods("GET")
m.HandleFunc("/{name}", middlewares.AuthMiddleware(app.Conf)(Publish(app.Logger, app.Conf))).Methods("PUT")
// tar handlers
m.HandleFunc("/{name}/-/{tar}", PackageTarGet(app.Logger, app.Conf)).Methods("GET")
// tag handlers
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(DistTagDelete(app.Logger, app.Conf))).Methods("DELETE")
m.HandleFunc("/-/package/{name}/dist-tags/{tag}", middlewares.AuthMiddleware(app.Conf)(DistTagPut(app.Logger, app.Conf))).Methods("PUT")
m.HandleFunc("/-/package/{name}/dist-tags", DistTagGet(app.Logger, app.Conf)).Methods("GET")
m.NotFoundHandler = http.HandlerFunc(NotFound)
app.Mux = m
}
func (app *Application) Start() error {
app.Routes()
server := &http.Server{
Addr: app.Conf.IpAddress,
Handler: app.Mux,
ReadTimeout: 4 * time.Second,
WriteTimeout: 4 * time.Second,
}
return server.ListenAndServe()
}

View File

@ -6,27 +6,33 @@ import (
"net/url" "net/url"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"gosimplenpm/config"
"gosimplenpm/storage" "gosimplenpm/storage"
) )
func Get(w http.ResponseWriter, r *http.Request) { func GetPackage(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
escapedName := mux.Vars(r)["name"] return func(w http.ResponseWriter, r *http.Request) {
packageName, _ := url.PathUnescape(escapedName) escapedName := mux.Vars(r)["name"]
fmt.Printf("Package name => %s\n", packageName) packageName, _ := url.PathUnescape(escapedName)
lg.WithFields(logrus.Fields{
"function": "get-package",
}).Debugf("Package name => %s\n", packageName)
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName) fileToServe, found, err := storage.GetIndexJsonFromStore(packageName, cfg.RepoDir, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
}
if !found {
ret := fmt.Sprintf("Package not found: %s", packageName)
http.Error(w, ret, http.StatusNotFound)
return
}
// serve file
http.ServeFile(w, r, fileToServe)
} }
if !found {
ret := fmt.Sprintf("Package not found: %s", packageName)
http.Error(w, ret, http.StatusNotFound)
return
}
// serve file
http.ServeFile(w, r, fileToServe)
} }

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"gosimplenpm/config"
"gosimplenpm/serviceidos" "gosimplenpm/serviceidos"
"gosimplenpm/storage" "gosimplenpm/storage"
"net/http" "net/http"
@ -11,111 +12,131 @@ import (
"strings" "strings"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/sirupsen/logrus"
) )
type NPMClientPutRequest struct { type NPMClientPutRequest struct {
Request serviceidos.IndexJson Request serviceidos.IndexJson
} }
func Publish(w http.ResponseWriter, r *http.Request) { func Publish(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
// (1) Parse Json Body return func(w http.ResponseWriter, r *http.Request) {
// (2) Check if package exists in the folder. // (1) Parse Json Body
// (a) if it does, ckeck if it is the same version. If it is, return error. Else modify index.json from (2) // (2) Check if package exists in the folder.
// (b) If it does not, add the latest tag to the new index.json // (a) if it does, ckeck if it is the same version. If it is, return error. Else modify index.json from (2)
// (b) If it does not, add the latest tag to the new index.json
escapedName := mux.Vars(r)["name"] escapedName := mux.Vars(r)["name"]
packageName, _ := url.PathUnescape(escapedName) packageName, _ := url.PathUnescape(escapedName)
fmt.Printf("Package name => %s\n", packageName) lg.WithFields(logrus.Fields{
"function": "publish",
}).Debugf("Package name => %s\n", packageName)
var cr NPMClientPutRequest var cr NPMClientPutRequest
// Parse json body // Parse json body
err := json.NewDecoder(r.Body).Decode(&cr.Request) err := json.NewDecoder(r.Body).Decode(&cr.Request)
if err != nil { if err != nil {
fmt.Printf("Error unmarshaling put request: %+v\n", err) lg.WithFields(logrus.Fields{
http.Error(w, err.Error(), http.StatusInternalServerError) "function": "publish",
return }).Debugf("Error unmarshaling put request: %+v\n", err)
} http.Error(w, err.Error(), http.StatusInternalServerError)
return
// Extract relevant data from index.json
index := 0
var tag string
var version string
var versionData serviceidos.IndexJsonVersions
// TODO: Fix this as the order is not guaranteed
for key, value := range cr.Request.DistTags {
if index == 0 {
tag = key
version = value
break
} }
index++
}
versionData = cr.Request.Versions[version]
fmt.Printf("For version(%s) with tag(%s), versionData => %+v\n", version, tag, versionData)
// Rewrite the tarball path // Extract relevant data from index.json
tarballFileName := strings.Split(versionData.Dist.Tarball, "/-/")[1] index := 0
fmt.Printf("TarballName => %s\n", tarballFileName) var tag string
// versionData.Dist.Tarball = fmt.Sprintf("file://%s", packageFilePath) var version string
versionData.Dist.Tarball = fmt.Sprintf("http://%s/%s/-/%s", r.Host, url.PathEscape(packageName), url.PathEscape(tarballFileName)) var versionData serviceidos.IndexJsonVersions
fmt.Printf("versionData.Dist.Tarball => %s\n", versionData.Dist.Tarball) // TODO: Fix this as the order is not guaranteed
registryPath, _ := storage.GetRegistryPath() for key, value := range cr.Request.DistTags {
tarBallFile := strings.Split(tarballFileName, "/")[1] if index == 0 {
packageFilePath := path.Join(registryPath, packageName, tarBallFile) tag = key
version = value
break
}
index++
}
versionData = cr.Request.Versions[version]
lg.WithFields(logrus.Fields{
"function": "publish",
}).Debugf("For version(%s) with tag(%s), versionData => %+v\n", version, tag, versionData)
// Try to get the index.json from the store // Rewrite the tarball path
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName) tarballFileName := strings.Split(versionData.Dist.Tarball, "/-/")[1]
if err != nil { lg.WithFields(logrus.Fields{
http.Error(w, err.Error(), http.StatusInternalServerError) "function": "publish",
return }).Debugf("TarballName => %s\n", tarballFileName)
} // versionData.Dist.Tarball = fmt.Sprintf("file://%s", packageFilePath)
versionData.Dist.Tarball = fmt.Sprintf("http://%s/%s/-/%s", r.Host, url.PathEscape(packageName), url.PathEscape(tarballFileName))
lg.WithFields(logrus.Fields{
"function": "publish",
}).Debugf("versionData.Dist.Tarball => %s\n", versionData.Dist.Tarball)
var jsonFile serviceidos.IndexJson tarBallFile := strings.Split(tarballFileName, "/")[1]
if !found { packageFilePath := path.Join(cfg.RepoDir, packageName, tarBallFile)
// new package
jsonFile = cr.Request // Try to get the index.json from the store
jsonFile.DistTags["latest"] = version fileToServe, found, err := storage.GetIndexJsonFromStore(packageName, cfg.RepoDir, lg)
} else {
// old package
err = storage.ReadIndexJson(fileToServe, &jsonFile)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
// Checking that you are not publishing over a pervious published version var jsonFile serviceidos.IndexJson
if jsonFile.Versions[version].Version == version { if !found {
fmt.Printf("Version %s of package %s already exists!!\n", version, packageName) // new package
http.Error(w, err.Error(), http.StatusBadRequest) jsonFile = cr.Request
jsonFile.DistTags["latest"] = version
} else {
// old package
err = storage.ReadIndexJson(fileToServe, &jsonFile, lg)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Checking that you are not publishing over a pervious published version
if jsonFile.Versions[version].Version == version {
lg.WithFields(logrus.Fields{
"function": "publish",
}).Debugf("Version %s of package %s already exists!!\n", version, packageName)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Rewrite attachments
jsonFile.DistTags[tag] = version
nAttachments := make(map[string]serviceidos.IndexJsonAttachments)
nAttachments[fmt.Sprintf("%s-%s.tgz", packageName, version)] = cr.Request.Attachments[fmt.Sprintf("%s-%s.tgz", packageName, version)]
jsonFile.Attachments = nAttachments
// Merge in the new version data
jsonFile.Versions[version] = versionData
}
lg.WithFields(logrus.Fields{
"function": "publish",
}).Debugln("FiletoServe ==> ", fileToServe)
// Write index.json
err = storage.WriteIndexJson(fileToServe, &jsonFile, lg)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
// Rewrite attachments lg.WithFields(logrus.Fields{
jsonFile.DistTags[tag] = version "function": "publish",
nAttachments := make(map[string]serviceidos.IndexJsonAttachments) }).Debugln("Package path => ", packageFilePath)
nAttachments[fmt.Sprintf("%s-%s.tgz", packageName, version)] = cr.Request.Attachments[fmt.Sprintf("%s-%s.tgz", packageName, version)] // Write bundled package
jsonFile.Attachments = nAttachments packageData := jsonFile.Attachments[fmt.Sprintf("%s-%s.tgz", packageName, version)].Data
err = storage.WritePackageToStore(packageFilePath, packageData, lg)
// Merge in the new version data if err != nil {
jsonFile.Versions[version] = versionData http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
} }
fmt.Println("FiletoServe ==> ", fileToServe)
// Write index.json
err = storage.WriteIndexJson(fileToServe, &jsonFile)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Println("Package path => ", packageFilePath)
// Write bundled package
packageData := jsonFile.Attachments[fmt.Sprintf("%s-%s.tgz", packageName, version)].Data
err = storage.WritePackageToStore(packageFilePath, packageData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
} }

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"gosimplenpm/config"
"gosimplenpm/serviceidos" "gosimplenpm/serviceidos"
"gosimplenpm/storage" "gosimplenpm/storage"
"net/http" "net/http"
@ -14,15 +15,19 @@ import (
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
) )
func DistTagDelete(lg *logrus.Logger) http.HandlerFunc { func DistTagDelete(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
escapedName := mux.Vars(r)["name"] escapedName := mux.Vars(r)["name"]
packageName, _ := url.PathUnescape(escapedName) packageName, _ := url.PathUnescape(escapedName)
lg.Printf("Package name => %s\n", packageName) lg.WithFields(logrus.Fields{
"function": "dist-tags-delete",
}).Debugf("Package name => %s\n", packageName)
escapedName = mux.Vars(r)["tag"] escapedName = mux.Vars(r)["tag"]
tag, _ := url.PathUnescape(escapedName) tag, _ := url.PathUnescape(escapedName)
lg.Printf("Tag => %s\n", tag) lg.WithFields(logrus.Fields{
"function": "dist-tags-delete",
}).Debugf("Tag => %s\n", tag)
if semver.IsValid(tag) { if semver.IsValid(tag) {
http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest) http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest)
@ -34,7 +39,7 @@ func DistTagDelete(lg *logrus.Logger) http.HandlerFunc {
return return
} }
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName) fileToServe, found, err := storage.GetIndexJsonFromStore(packageName, cfg.RepoDir, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -47,7 +52,7 @@ func DistTagDelete(lg *logrus.Logger) http.HandlerFunc {
} }
var jsonFile serviceidos.IndexJson var jsonFile serviceidos.IndexJson
err = storage.ReadIndexJson(fileToServe, &jsonFile) err = storage.ReadIndexJson(fileToServe, &jsonFile, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -56,7 +61,7 @@ func DistTagDelete(lg *logrus.Logger) http.HandlerFunc {
delete(jsonFile.DistTags, tag) delete(jsonFile.DistTags, tag)
// Write index.json // Write index.json
err = storage.WriteIndexJson(fileToServe, &jsonFile) err = storage.WriteIndexJson(fileToServe, &jsonFile, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"gosimplenpm/config"
"gosimplenpm/serviceidos" "gosimplenpm/serviceidos"
"gosimplenpm/storage" "gosimplenpm/storage"
"net/http" "net/http"
@ -13,13 +14,15 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
func DistTagGet(lg *logrus.Logger) http.HandlerFunc { func DistTagGet(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
escapedName := mux.Vars(r)["name"] escapedName := mux.Vars(r)["name"]
packageName, _ := url.PathUnescape(escapedName) packageName, _ := url.PathUnescape(escapedName)
lg.Debugf("Package name => %s\n", packageName) lg.WithFields(logrus.Fields{
"function": "dist-tags-get",
}).Debugf("Package name => %s\n", packageName)
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName) fileToServe, found, err := storage.GetIndexJsonFromStore(packageName, cfg.RepoDir, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -32,7 +35,7 @@ func DistTagGet(lg *logrus.Logger) http.HandlerFunc {
} }
var jsonFile serviceidos.IndexJson var jsonFile serviceidos.IndexJson
err = storage.ReadIndexJson(fileToServe, &jsonFile) err = storage.ReadIndexJson(fileToServe, &jsonFile, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"gosimplenpm/config"
"gosimplenpm/serviceidos" "gosimplenpm/serviceidos"
"gosimplenpm/storage" "gosimplenpm/storage"
"io" "io"
@ -15,15 +16,19 @@ import (
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
) )
func DistTagPut(lg *logrus.Logger) http.HandlerFunc { func DistTagPut(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
escapedName := mux.Vars(r)["name"] escapedName := mux.Vars(r)["name"]
packageName, _ := url.PathUnescape(escapedName) packageName, _ := url.PathUnescape(escapedName)
lg.Printf("Package name => %s\n", packageName) lg.WithFields(logrus.Fields{
"function": "dist-tags-put",
}).Debugf("Package name => %s\n", packageName)
escapedName = mux.Vars(r)["tag"] escapedName = mux.Vars(r)["tag"]
tag, _ := url.PathUnescape(escapedName) tag, _ := url.PathUnescape(escapedName)
lg.Printf("Tag => %s\n", tag) lg.WithFields(logrus.Fields{
"function": "dist-tags-put",
}).Debugf("Tag => %s\n", tag)
if semver.IsValid(tag) { if semver.IsValid(tag) {
http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest) http.Error(w, "Tag cannot be a semver version", http.StatusBadRequest)
@ -38,9 +43,11 @@ func DistTagPut(lg *logrus.Logger) http.HandlerFunc {
body, _ := io.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
var version string var version string
_ = json.Unmarshal(body, &version) _ = json.Unmarshal(body, &version)
lg.Printf("Body => %s", version) lg.WithFields(logrus.Fields{
"function": "dist-tags-put",
}).Debugf("Body => %s", version)
fileToServe, found, err := storage.GetIndexJsonFromStore(packageName) fileToServe, found, err := storage.GetIndexJsonFromStore(packageName, cfg.RepoDir, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -53,7 +60,7 @@ func DistTagPut(lg *logrus.Logger) http.HandlerFunc {
} }
var jsonFile serviceidos.IndexJson var jsonFile serviceidos.IndexJson
err = storage.ReadIndexJson(fileToServe, &jsonFile) err = storage.ReadIndexJson(fileToServe, &jsonFile, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
@ -62,7 +69,7 @@ func DistTagPut(lg *logrus.Logger) http.HandlerFunc {
jsonFile.DistTags[tag] = version jsonFile.DistTags[tag] = version
// Write index.json // Write index.json
err = storage.WriteIndexJson(fileToServe, &jsonFile) err = storage.WriteIndexJson(fileToServe, &jsonFile, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return

View File

@ -2,7 +2,7 @@ package handler
import ( import (
"bytes" "bytes"
"fmt" "gosimplenpm/config"
"gosimplenpm/storage" "gosimplenpm/storage"
"io" "io"
"net/http" "net/http"
@ -11,33 +11,40 @@ import (
"strings" "strings"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/sirupsen/logrus"
) )
func Tar(w http.ResponseWriter, r *http.Request) { func PackageTarGet(lg *logrus.Logger, cfg config.Config) http.HandlerFunc {
// Sample output of npm view return func(w http.ResponseWriter, r *http.Request) {
// Public // Sample output of npm view
// dist // Public
// .tarball: https://registry.npmjs.org/react/-/react-18.2.0.tgz // dist
// LocalHost // .tarball: https://registry.npmjs.org/react/-/react-18.2.0.tgz
// dist // LocalHost
// .tarball: http://localhost:4000/@ookusanya/package1/-/package1-0.2.0.tgz // dist
// .tarball: http://localhost:4000/@ookusanya/package1/-/package1-0.2.0.tgz
escapedName := mux.Vars(r)["name"] escapedName := mux.Vars(r)["name"]
packageName, _ := url.PathUnescape(escapedName) packageName, _ := url.PathUnescape(escapedName)
fmt.Printf("Package name => %s\n", packageName) lg.WithFields(logrus.Fields{
escapedName = mux.Vars(r)["tar"] "function": "get-tar",
tarFileName, _ := url.PathUnescape(escapedName) }).Debugf("Package name => %s\n", packageName)
fmt.Printf("Tarfile name => %s\n", tarFileName) escapedName = mux.Vars(r)["tar"]
tarFileName, _ := url.PathUnescape(escapedName)
lg.WithFields(logrus.Fields{
"function": "get-tar",
}).Debugf("Tarfile name => %s\n", tarFileName)
versionName := strings.Split(strings.Split(tarFileName, "-")[1], ".tgz")[0] versionName := strings.Split(strings.Split(tarFileName, "-")[1], ".tgz")[0]
fileAsString, err := storage.GetTarFromStore(packageName, versionName) fileAsString, err := storage.GetTarFromStore(packageName, versionName, cfg.RepoDir, lg)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
}
// Sending the tar as a base64 string
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", strconv.Itoa(len([]byte(fileAsString))))
io.Copy(w, bytes.NewReader([]byte(fileAsString)))
} }
// Sending the tar as a base64 string
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", strconv.Itoa(len([]byte(fileAsString))))
io.Copy(w, bytes.NewReader([]byte(fileAsString)))
} }

35
main.go Normal file
View File

@ -0,0 +1,35 @@
package main
import (
"gosimplenpm/cmd/gosimplenpm"
)
func main() {
gosimplenpm.Execute()
}
// func main() {
// log := &logrus.Logger{
// Out: os.Stdout,
// Level: logrus.DebugLevel,
// Formatter: &logrus.TextFormatter{
// FullTimestamp: true,
// TimestampFormat: "2009-01-02 15:15:15",
// },
// }
// var cfg config.Config
// err := config.LoadConfiguration("userdata/config.json", &cfg)
// if err != nil {
// log.Fatalf("Config is not loaded: %+v\n", err)
// }
// app := &gosimplenpm.Application{
// Conf: cfg,
// Logger: log,
// }
// log.Infoln("Starting server on port 4000")
// err = http.ListenAndServe(":4000", app.Routes())
// log.Fatal(err)
// }

View File

@ -14,26 +14,15 @@ import (
"gosimplenpm/serviceidos" "gosimplenpm/serviceidos"
"path/filepath" "path/filepath"
"github.com/sirupsen/logrus"
) )
func GetRegistryPath() (string, error) { func GetIndexJsonFromStore(packageName string, registryPath string, log *logrus.Logger) (string, bool, error) {
registryPath, err := filepath.Abs("./examples")
if err != nil {
fmt.Printf("File repo not found: +%v\n", err)
return "", err
}
return registryPath, err
}
func GetIndexJsonFromStore(packageName string) (string, bool, error) {
fileToServe := "" fileToServe := ""
found := false found := false
searchDir, err := GetRegistryPath()
if err != nil {
return searchDir, found, err
}
err = filepath.WalkDir(searchDir, func(fp string, info fs.DirEntry, e error) error { err := filepath.WalkDir(registryPath, func(fp string, info fs.DirEntry, e error) error {
if strings.Contains(fp, path.Join(packageName, "index.json")) { if strings.Contains(fp, path.Join(packageName, "index.json")) {
fileToServe = fp fileToServe = fp
found = true found = true
@ -42,25 +31,23 @@ func GetIndexJsonFromStore(packageName string) (string, bool, error) {
}) })
if err != nil { if err != nil {
fmt.Printf("List files error: +%v\n", err) log.WithFields(logrus.Fields{
"function": "get-index-json-from-store",
}).Debugf("List files error: +%v\n", err)
return fileToServe, found, err return fileToServe, found, err
} }
if fileToServe == "" && !found { if fileToServe == "" && !found {
fileToServe = path.Join(searchDir, packageName, "index.json") fileToServe = path.Join(registryPath, packageName, "index.json")
} }
return fileToServe, found, nil return fileToServe, found, nil
} }
func GetTarFromStore(packageName string, tarFileName string) (string, error) { func GetTarFromStore(packageName string, tarFileName string, registryPath string, log *logrus.Logger) (string, error) {
fileToServe := "" fileToServe := ""
searchDir, err := GetRegistryPath()
if err != nil {
return searchDir, err
}
err = filepath.WalkDir(searchDir, func(fp string, info fs.DirEntry, e error) error { err := filepath.WalkDir(registryPath, func(fp string, info fs.DirEntry, e error) error {
if strings.Contains(fp, path.Join(packageName, tarFileName)) { if strings.Contains(fp, path.Join(packageName, tarFileName)) {
fileToServe = fp fileToServe = fp
} }
@ -68,7 +55,9 @@ func GetTarFromStore(packageName string, tarFileName string) (string, error) {
}) })
if err != nil { if err != nil {
fmt.Printf("List files error: +%v\n", err) log.WithFields(logrus.Fields{
"function": "get-tar-from-store",
}).Debugf("List files error: +%v\n", err)
return fileToServe, err return fileToServe, err
} }
@ -78,29 +67,37 @@ func GetTarFromStore(packageName string, tarFileName string) (string, error) {
file, err := os.Open(fileToServe) file, err := os.Open(fileToServe)
if err != nil { if err != nil {
fmt.Printf("Open error: %s\n", fileToServe) log.WithFields(logrus.Fields{
"function": "get-tar-from-store",
}).Debugf("Open error: %s\n", fileToServe)
return "", err return "", err
} }
archive, err := gzip.NewReader(file) archive, err := gzip.NewReader(file)
if err != nil { if err != nil {
fmt.Printf("Archive Open error: %s\n", fileToServe) log.WithFields(logrus.Fields{
"function": "get-tar-from-store",
}).Debugf("Archive Open error: %s\n", fileToServe)
return "", err return "", err
} }
tr := tar.NewReader(archive) tr := tar.NewReader(archive)
bs, err := io.ReadAll(tr) bs, err := io.ReadAll(tr)
if err != nil { if err != nil {
fmt.Printf("Archive Read error: %s\n", fileToServe) log.WithFields(logrus.Fields{
"function": "get-tar-from-store",
}).Debugf("Archive Read error: %s\n", fileToServe)
return "", err return "", err
} }
return base64.StdEncoding.EncodeToString(bs), err return base64.StdEncoding.EncodeToString(bs), err
} }
func ReadIndexJson(fPath string, res *serviceidos.IndexJson) error { func ReadIndexJson(fPath string, res *serviceidos.IndexJson, log *logrus.Logger) error {
jsonFile, err := os.Open(fPath) jsonFile, err := os.Open(fPath)
if err != nil { if err != nil {
fmt.Printf("File Not found: %s\n", fPath) log.WithFields(logrus.Fields{
"function": "read-index-json",
}).Debugf("File Not found: %s\n", fPath)
return err return err
} }
@ -108,19 +105,23 @@ func ReadIndexJson(fPath string, res *serviceidos.IndexJson) error {
err = json.NewDecoder(jsonFile).Decode(res) err = json.NewDecoder(jsonFile).Decode(res)
if err != nil { if err != nil {
fmt.Printf("Unmarshalerror: %+v\n", err) log.WithFields(logrus.Fields{
"function": "read-index-json",
}).Debugf("Unmarshalerror: %+v\n", err)
return err return err
} }
return nil return nil
} }
func WriteIndexJson(fPath string, res *serviceidos.IndexJson) error { func WriteIndexJson(fPath string, res *serviceidos.IndexJson, log *logrus.Logger) error {
// Need to create the directory first // Need to create the directory first
parent := path.Dir(fPath) parent := path.Dir(fPath)
err := os.MkdirAll(parent, os.ModePerm) err := os.MkdirAll(parent, os.ModePerm)
if err != nil { if err != nil {
fmt.Printf("Folder (%s) creation failed.\n", fPath) log.WithFields(logrus.Fields{
"function": "write-index-json",
}).Debugf("Folder (%s) creation failed.\n", fPath)
return err return err
} }
@ -128,7 +129,9 @@ func WriteIndexJson(fPath string, res *serviceidos.IndexJson) error {
jsonFile, err := os.Create(fPath) jsonFile, err := os.Create(fPath)
if err != nil { if err != nil {
fmt.Printf("Creation error for path(%s): %+v\n ", fPath, err) log.WithFields(logrus.Fields{
"function": "write-index-json",
}).Debugf("Creation error for path(%s): %+v\n ", fPath, err)
return err return err
} }
@ -136,23 +139,29 @@ func WriteIndexJson(fPath string, res *serviceidos.IndexJson) error {
err = json.NewEncoder(jsonFile).Encode(res) err = json.NewEncoder(jsonFile).Encode(res)
if err != nil { if err != nil {
fmt.Printf("Marshalerror: %+v\n", err) log.WithFields(logrus.Fields{
"function": "write-index-json",
}).Debugf("Marshalerror: %+v\n", err)
return err return err
} }
return nil return nil
} }
func WritePackageToStore(fPath string, data string) error { func WritePackageToStore(fPath string, data string, log *logrus.Logger) error {
dec, err := base64.StdEncoding.DecodeString(data) dec, err := base64.StdEncoding.DecodeString(data)
if err != nil { if err != nil {
fmt.Printf("Base64 Decode error: %+v\n", err) log.WithFields(logrus.Fields{
"function": "write-package-to-store",
}).Debugf("Base64 Decode error: %+v\n", err)
return err return err
} }
dataFile, err := os.Create(fPath) dataFile, err := os.Create(fPath)
if err != nil { if err != nil {
fmt.Printf("Creation error: %s\n", fPath) log.WithFields(logrus.Fields{
"function": "write-package-to-store",
}).Debugf("Creation error: %s\n", fPath)
return err return err
} }
@ -160,13 +169,17 @@ func WritePackageToStore(fPath string, data string) error {
_, err = dataFile.Write(dec) _, err = dataFile.Write(dec)
if err != nil { if err != nil {
fmt.Printf("Write error: %s\n", fPath) log.WithFields(logrus.Fields{
"function": "write-package-to-store",
}).Debugf("Write error: %s\n", fPath)
return err return err
} }
err = dataFile.Sync() err = dataFile.Sync()
if err != nil { if err != nil {
fmt.Printf("Sync error: %s\n", fPath) log.WithFields(logrus.Fields{
"function": "write-package-to-store",
}).Debugf("Sync error: %s\n", fPath)
return err return err
} }