forked from oreonproject/eternity
Added support for repo generate
and some other various improvements
This commit is contained in:
parent
0dbea32590
commit
714b62de11
5 changed files with 388 additions and 30 deletions
BIN
cmd/cmd
BIN
cmd/cmd
Binary file not shown.
22
cmd/main.go
22
cmd/main.go
|
@ -4,6 +4,7 @@ import (
|
|||
"eternity/common"
|
||||
"eternity/lib"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
@ -55,11 +56,13 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
tempDir, err, vagueError = lib.BuildEPK("./", inMemory, config.Build, logger)
|
||||
var size big.Int
|
||||
size, tempDir, err, vagueError = lib.BuildEPK("./", inMemory, config.Build, logger)
|
||||
if err != nil || vagueError != nil {
|
||||
common.BuildEPKHandleError(tempDir, err, vagueError, logger)
|
||||
} else {
|
||||
filePath := filepath.Join("./", config.Metadata.Name+"-"+config.Metadata.Version.String())
|
||||
config.Metadata.DecompressedSize = size
|
||||
err, vagueError := lib.PackageEPK(config.Metadata, config.Build, tempDir, filePath+".epk", privateKey, logger)
|
||||
if err != nil || vagueError != nil {
|
||||
common.PackageEPKHandleError(err, vagueError, logger)
|
||||
|
@ -72,6 +75,23 @@ func main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
case "repo":
|
||||
if len(os.Args) < 4 {
|
||||
fmt.Println("Usage: eternity repo <build/generate> <directory>")
|
||||
fmt.Println("See 'eternity help repo' for more information.")
|
||||
os.Exit(1)
|
||||
}
|
||||
privateKey, err, vagueError := common.LoadPrivateKey(logger)
|
||||
if err != nil || vagueError != nil {
|
||||
common.LoadPrivateKeyHandleError(err, vagueError, logger)
|
||||
}
|
||||
switch os.Args[2] {
|
||||
case "generate":
|
||||
err, vagueError := lib.GenerateRepository(os.Args[3], privateKey, logger)
|
||||
if err != nil || vagueError != nil {
|
||||
common.GenerateRepositoryHandleError(err, vagueError, logger)
|
||||
}
|
||||
}
|
||||
case "help":
|
||||
if len(os.Args) > 2 {
|
||||
switch os.Args[2] {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/ed25519"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
@ -35,13 +36,13 @@ var DefaultLogger = lib.Logger{
|
|||
fmt.Println(severityPretty, log.Content)
|
||||
if log.Prompt {
|
||||
fmt.Print(": ")
|
||||
var userInput string
|
||||
_, err := fmt.Scanln(&userInput)
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
userInput, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString("[FATAL]"), "Failed to read user input:", err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
return userInput
|
||||
return userInput[:len(userInput)-1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
@ -154,6 +155,11 @@ func BuildEPKHandleError(tempDir string, err error, vagueError error, logger *li
|
|||
Level: "FATAL",
|
||||
Content: "Failed to count files in target root: " + err.Error(),
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrBuildEPKBadBuildType):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Invalid build type: " + err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,3 +388,50 @@ func LoadPrivateKeyHandleError(err error, vagueError error, logger *lib.Logger)
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateRepositoryHandleError(err error, vagueError error, logger *lib.Logger) {
|
||||
switch {
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryStatError):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to stat directory: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryNotDirectory):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Specified path is not a directory",
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryFailedToWalk):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to walk directory: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryCannotMarshalJSON):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to marshal JSON: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryCannotOpenFile):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to open file for writing: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryCannotWriteFile):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to write to file: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
case errors.Is(vagueError, lib.ErrGenerateRepositoryCannotCloseFile):
|
||||
logger.LogFunc(lib.Log{
|
||||
Level: "FATAL",
|
||||
Content: "Failed to close file: " + err.Error(),
|
||||
Prompt: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,4 +8,3 @@
|
|||
</magic>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
|
||||
|
|
330
lib/main.go
330
lib/main.go
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -34,6 +35,8 @@ type Metadata struct {
|
|||
Author string
|
||||
License string
|
||||
Architecture string
|
||||
// The decompressed size may be larger than the int64 allocated for a compressed file
|
||||
DecompressedSize big.Int
|
||||
Dependencies []string
|
||||
SpecialFiles SpecialFiles
|
||||
}
|
||||
|
@ -256,16 +259,17 @@ var ErrBuildEPKWritingBuildShError = errors.New("error writing to build.sh")
|
|||
var ErrBuildEPKTargetRootError = errors.New("error creating target root")
|
||||
var ErrBuildEPKExecutingBuildShError = errors.New("error executing build.sh")
|
||||
var ErrBuildEPKCountingFilesError = errors.New("error counting files")
|
||||
var ErrBuildEPKBadBuildType = errors.New("bad build type")
|
||||
|
||||
// BuildEPK builds the EPK package into a build directory
|
||||
func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logger) (string, error, error) {
|
||||
func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logger) (big.Int, string, error, error) {
|
||||
var tempDir string
|
||||
|
||||
switch buildConfig.Type {
|
||||
case "chroot":
|
||||
return "", nil, ErrBuildEPKChrootError
|
||||
return *big.NewInt(0), "", nil, ErrBuildEPKChrootError
|
||||
case "unrestricted":
|
||||
return "", nil, ErrBuildEPKUnrestrictedError
|
||||
return *big.NewInt(0), "", nil, ErrBuildEPKUnrestrictedError
|
||||
case "host":
|
||||
// Set up the temp dir
|
||||
var err error
|
||||
|
@ -279,7 +283,7 @@ func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logge
|
|||
tempDir, err = os.MkdirTemp(projectDir, "eternity-build-")
|
||||
}
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKTemporaryDirectoryError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKTemporaryDirectoryError
|
||||
}
|
||||
|
||||
// Copy the hooks folder
|
||||
|
@ -292,12 +296,12 @@ func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logge
|
|||
|
||||
err = os.MkdirAll(targetHooksDir, 0755)
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKCreateHooksError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKCreateHooksError
|
||||
}
|
||||
|
||||
err = os.CopyFS(targetHooksDir, os.DirFS(hooksDir))
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKCopyHooksError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKCopyHooksError
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,19 +318,19 @@ func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logge
|
|||
|
||||
file, err := os.OpenFile(tempDir+"/build.sh", os.O_CREATE|os.O_RDWR, 0755)
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKBuildShError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKBuildShError
|
||||
}
|
||||
|
||||
_, err = file.WriteString(shellScript)
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKWritingBuildShError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKWritingBuildShError
|
||||
}
|
||||
|
||||
// Set up the target root
|
||||
targetRoot := filepath.Join(tempDir, buildConfig.TargetRoot)
|
||||
err = os.MkdirAll(targetRoot, 0755)
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKTargetRootError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKTargetRootError
|
||||
}
|
||||
|
||||
// Execute the shell script in BWrap
|
||||
|
@ -369,11 +373,12 @@ func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logge
|
|||
|
||||
err = exec.Command("bwrap", arguments...).Run()
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKExecutingBuildShError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKExecutingBuildShError
|
||||
}
|
||||
|
||||
// Hopefully, the build was successful. Let's give the user a file count.
|
||||
// Hopefully, the build was successful. Let's give the user a file and size count.
|
||||
var fileCount int
|
||||
var sizeCount big.Int
|
||||
// We start at -1 because the root directory is not counted
|
||||
dirCount := -1
|
||||
err = filepath.Walk(targetRoot, func(path string, info os.FileInfo, err error) error {
|
||||
|
@ -382,18 +387,25 @@ func BuildEPK(projectDir string, inMemory bool, buildConfig Build, logger *Logge
|
|||
} else {
|
||||
fileCount++
|
||||
}
|
||||
// Both directories and files need to have their sizes counted
|
||||
sizeCount.Add(&sizeCount, big.NewInt(info.Size()))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return tempDir, err, ErrBuildEPKCountingFilesError
|
||||
return *big.NewInt(0), tempDir, err, ErrBuildEPKCountingFilesError
|
||||
}
|
||||
|
||||
logger.LogFunc(Log{
|
||||
Level: "INFO", Content: "Build successful. " + strconv.Itoa(fileCount) + " files and " + strconv.Itoa(dirCount) + " directories created.", Prompt: false,
|
||||
Level: "INFO",
|
||||
Content: "Build successful. " + strconv.Itoa(fileCount) + " files and " + strconv.Itoa(dirCount) +
|
||||
" directories created," + " totalling " + sizeCount.String() + " bytes.",
|
||||
Prompt: false,
|
||||
})
|
||||
}
|
||||
|
||||
return tempDir, nil, nil
|
||||
return sizeCount, tempDir, nil, nil
|
||||
default:
|
||||
return *big.NewInt(0), "", errors.New(buildConfig.Type), ErrBuildEPKBadBuildType
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTar creates a tar archive from a directory
|
||||
|
@ -463,13 +475,13 @@ var ConstPackageEPKBigEndian = []byte{0x62}
|
|||
var ConstPackageEPKLittleEndian = []byte{0x6C}
|
||||
|
||||
// ConstPackageEPKInitialByteOffset is the initial byte offset for an EPK file until we arrive at the signature. 12 = 3 + 1 + 8: 3 for the magic number, 1 for the endian, and 8 for the tar offset
|
||||
var ConstPackageEPKInitialByteOffset = 12
|
||||
var ConstPackageEPKInitialByteOffset int64 = 12
|
||||
|
||||
// SignatureLength is the length of the signature
|
||||
var SignatureLength = 64
|
||||
// ConstPackageEPKSignatureLength is the length of the signature
|
||||
var ConstPackageEPKSignatureLength int64 = 64
|
||||
|
||||
// PublicKeyLength is the length of the public key
|
||||
var PublicKeyLength = 32
|
||||
// ConstPackageEPKPublicKeyLength is the length of the public key
|
||||
var ConstPackageEPKPublicKeyLength int64 = 32
|
||||
|
||||
// ConstPackageEPKMetadataOffset is the offset of the metadata in the EPK file
|
||||
var ConstPackageEPKMetadataOffset = 108
|
||||
|
@ -536,6 +548,7 @@ func PackageEPK(metaData Metadata, build Build, tempDir string, output string, p
|
|||
"noDelete": metaData.SpecialFiles.NoDelete,
|
||||
"noReplace": metaData.SpecialFiles.NoReplace,
|
||||
},
|
||||
"size": metaData.DecompressedSize.String(),
|
||||
}
|
||||
|
||||
// Make the data template into a JSON string
|
||||
|
@ -690,13 +703,13 @@ func PackageEPK(metaData Metadata, build Build, tempDir string, output string, p
|
|||
}
|
||||
|
||||
// Write the signature
|
||||
_, err = file.WriteAt(signature, int64(ConstPackageEPKInitialByteOffset))
|
||||
_, err = file.WriteAt(signature, ConstPackageEPKInitialByteOffset)
|
||||
if err != nil {
|
||||
return err, ErrPackageEPKCannotWriteFile
|
||||
}
|
||||
|
||||
// Write the public key
|
||||
_, err = file.WriteAt(publicKey, int64(ConstPackageEPKInitialByteOffset)+int64(SignatureLength))
|
||||
_, err = file.WriteAt(publicKey, ConstPackageEPKInitialByteOffset+ConstPackageEPKSignatureLength)
|
||||
if err != nil {
|
||||
return err, ErrPackageEPKCannotWriteFile
|
||||
}
|
||||
|
@ -709,3 +722,276 @@ func PackageEPK(metaData Metadata, build Build, tempDir string, output string, p
|
|||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ConstGenerateRepositoryRepoDataOffset is the offset of the repository data in the repository.json file: it is 3 (magic) + 64 (the signature) + 32 (the public key) = 99
|
||||
var ConstGenerateRepositoryRepoDataOffset int64 = 99
|
||||
|
||||
// ConstGenerateRepositoryEPKMagicNumber is the magic number for an EPK repository: "eon" in ASCII / UTF-8, for obvious reasons
|
||||
var ConstGenerateRepositoryEPKMagicNumber = []byte{0x65, 0x6F, 0x6E}
|
||||
|
||||
var ErrGenerateRepositoryStatError = errors.New("error stating file or directory")
|
||||
var ErrGenerateRepositoryNotDirectory = errors.New("not a directory")
|
||||
var ErrGenerateRepositoryRepositoryNameContainsSlash = errors.New("repository name contains a slash")
|
||||
var ErrGenerateRepositoryFailedToWalk = errors.New("error walking directory")
|
||||
var ErrGenerateRepositoryCannotUnmarshalJSON = errors.New("error unmarshalling JSON")
|
||||
var ErrGenerateRepositoryCannotMarshalJSON = errors.New("error marshalling JSON")
|
||||
var ErrGenerateRepositoryCannotOpenFile = errors.New("error opening file for writing")
|
||||
var ErrGenerateRepositoryCannotWriteFile = errors.New("error writing to file")
|
||||
var ErrGenerateRepositoryCannotCloseFile = errors.New("error closing file")
|
||||
|
||||
func GenerateRepository(directory string, privateKey ed25519.PrivateKey, logger *Logger) (error, error) {
|
||||
// First, we need to see if the directory exists
|
||||
logger.LogFunc(Log{
|
||||
Level: "INFO", Content: "Generating repository", Prompt: false,
|
||||
})
|
||||
|
||||
info, err := os.Stat(directory)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryStatError
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil, ErrGenerateRepositoryNotDirectory
|
||||
}
|
||||
|
||||
// Create the EPK map
|
||||
epkMap := make(map[string]interface{})
|
||||
|
||||
// See if the repository.json file exists
|
||||
_, err = os.Stat(directory + "/repository.erf")
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return err, ErrGenerateRepositoryStatError
|
||||
} else {
|
||||
if logger.PromptSupported {
|
||||
// Ask the user for the name of the repository
|
||||
repoName := logger.LogFunc(Log{
|
||||
Level: "PROMPT", Content: "Enter the name of the repository", Prompt: true,
|
||||
})
|
||||
|
||||
// Check the repository name does not contain any slashes
|
||||
if strings.Contains(repoName, "/") {
|
||||
return nil, ErrGenerateRepositoryRepositoryNameContainsSlash
|
||||
}
|
||||
|
||||
// Ask the user for the description of the repository
|
||||
repoDesc := logger.LogFunc(Log{
|
||||
Level: "PROMPT", Content: "Enter a short description of the repository", Prompt: true,
|
||||
})
|
||||
|
||||
// Ask the user for the author of the repository
|
||||
repoAuthor := logger.LogFunc(Log{
|
||||
Level: "PROMPT",
|
||||
Content: "Enter your preferred author name. This must be the same as the author name used in " +
|
||||
"eternity.json and associated with your keypair, otherwise it will cause issues with EPK" +
|
||||
" verification and your repository will be rejected by Eon and cannot be trusted.",
|
||||
Prompt: true,
|
||||
})
|
||||
|
||||
// Now append the metadata to the EPK map
|
||||
epkMap["name"] = repoName
|
||||
epkMap["desc"] = repoDesc
|
||||
epkMap["author"] = repoAuthor
|
||||
} else {
|
||||
logger.LogFunc(Log{
|
||||
Level: "FATAL",
|
||||
Content: "Please fill in the author, name, and description of the repository in repository.json. " +
|
||||
"Your author name must be the same as the author name used in eternity.json and associated with " +
|
||||
"your keypair, otherwise it will cause issues with EPK verification and your repository will be " +
|
||||
"rejected by Eon and cannot be trusted.",
|
||||
Prompt: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Since it does exist, we can extract the name and description from it
|
||||
file, err := os.ReadFile(directory + "/repository.erf")
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotOpenFile
|
||||
}
|
||||
|
||||
// Unmarshal the JSON
|
||||
var oldRepositoryMap map[string]interface{}
|
||||
|
||||
err = json.Unmarshal(file[ConstGenerateRepositoryRepoDataOffset:], &oldRepositoryMap)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotUnmarshalJSON
|
||||
}
|
||||
|
||||
// Copy the author, name, and description to the EPK map
|
||||
epkMap["name"] = oldRepositoryMap["name"]
|
||||
epkMap["desc"] = oldRepositoryMap["desc"]
|
||||
epkMap["author"] = oldRepositoryMap["author"]
|
||||
}
|
||||
|
||||
// Add a list of packages to the EPK map
|
||||
epkMap["packages"] = make([]map[string]interface{}, 0)
|
||||
|
||||
// Now, walk the directory
|
||||
err = filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
|
||||
// If error is not nil, return it
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ignore directories
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ok. We need to check if the file actually is an EPK file
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read the first 3 bytes
|
||||
magicNumber := make([]byte, 3)
|
||||
_, err = file.Read(magicNumber)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the magic number is correct
|
||||
if !bytes.Equal(magicNumber, ConstPackageEPKMagicNumber) {
|
||||
// It isn't an EPK file, so we can ignore it
|
||||
return nil
|
||||
}
|
||||
|
||||
// We need to create a hash of the file
|
||||
xxHash := xxhash.New()
|
||||
_, err = io.Copy(xxHash, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract the metadata. First, we get the endian-ness
|
||||
var littleEndian bool
|
||||
endian := make([]byte, 1)
|
||||
_, err = file.ReadAt(endian, 3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(endian, ConstPackageEPKLittleEndian) {
|
||||
littleEndian = true
|
||||
} else if bytes.Equal(endian, ConstPackageEPKBigEndian) {
|
||||
littleEndian = false
|
||||
} else {
|
||||
return errors.New("invalid endianness")
|
||||
}
|
||||
|
||||
// Now we get the tar offset
|
||||
var tarOffset int64
|
||||
tarOffsetBytes := make([]byte, 8)
|
||||
_, err = file.ReadAt(tarOffsetBytes, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now we convert the tar offset to an int64
|
||||
if littleEndian {
|
||||
tarOffset = int64(binary.LittleEndian.Uint64(tarOffsetBytes))
|
||||
} else {
|
||||
tarOffset = int64(binary.BigEndian.Uint64(tarOffsetBytes))
|
||||
}
|
||||
|
||||
// Now we can read in the metadata
|
||||
metadataBytes := make([]byte, tarOffset-int64(ConstPackageEPKMetadataOffset))
|
||||
_, err = file.ReadAt(metadataBytes, int64(ConstPackageEPKMetadataOffset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now we can unmarshal the metadata
|
||||
var metadata map[string]interface{}
|
||||
err = json.Unmarshal(metadataBytes, &metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now we have the hash, we need to add it to our data template
|
||||
dataTemplate := make(map[string]interface{})
|
||||
dataTemplate["hash"] = xxHash.Sum64()
|
||||
|
||||
// Now we add some basic metadata
|
||||
dataTemplate["name"] = metadata["name"]
|
||||
dataTemplate["author"] = metadata["author"]
|
||||
dataTemplate["version"] = metadata["version"]
|
||||
dataTemplate["size"] = metadata["size"]
|
||||
dataTemplate["arch"] = metadata["arch"]
|
||||
dataTemplate["desc"] = metadata["desc"]
|
||||
dataTemplate["deps"] = metadata["deps"]
|
||||
|
||||
// We add the path to the EPK file, relative to the directory
|
||||
relativePath, err := filepath.Rel(directory, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataTemplate["path"] = relativePath
|
||||
|
||||
// Append it to a list in the EPK map
|
||||
epkMap["packages"] = append(epkMap["packages"].([]map[string]interface{}), dataTemplate)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// This error message is a bit vague, but meh.
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryFailedToWalk
|
||||
}
|
||||
|
||||
// Great, now we need to marshal the EPK map and write it to a file
|
||||
epkMapBytes, err := json.Marshal(epkMap)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotMarshalJSON
|
||||
}
|
||||
|
||||
// Write the EPK map to a file
|
||||
file, err := os.OpenFile(directory+"/repository.erf", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotOpenFile
|
||||
}
|
||||
|
||||
// Sign the epk map
|
||||
xxHash := xxhash.New()
|
||||
_, err = xxHash.Write(epkMapBytes)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
signature := ed25519.Sign(privateKey, xxHash.Sum(nil))
|
||||
publicKey := privateKey.Public().(ed25519.PublicKey)
|
||||
|
||||
// Write magic number
|
||||
_, err = file.Write(ConstGenerateRepositoryEPKMagicNumber)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotWriteFile
|
||||
}
|
||||
|
||||
// Write signature
|
||||
_, err = file.WriteAt(signature, 3)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotWriteFile
|
||||
}
|
||||
|
||||
// Write public key
|
||||
_, err = file.WriteAt(publicKey, 67)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotWriteFile
|
||||
}
|
||||
|
||||
// Write the EPK map to the file
|
||||
_, err = file.WriteAt(epkMapBytes, ConstGenerateRepositoryRepoDataOffset)
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotWriteFile
|
||||
}
|
||||
|
||||
// Close the file
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return err, ErrGenerateRepositoryCannotCloseFile
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue