mirror of https://github.com/aptly-dev/aptly
151 lines
3.4 KiB
Go
151 lines
3.4 KiB
Go
package pgp
|
|
|
|
import (
|
|
"errors"
|
|
"os/exec"
|
|
"regexp"
|
|
)
|
|
|
|
// GPGVersion stores discovered GPG version
|
|
type GPGVersion int
|
|
|
|
// GPG version as discovered
|
|
const (
|
|
GPG1x GPGVersion = 1
|
|
GPG20x GPGVersion = 2
|
|
GPG21x GPGVersion = 3
|
|
GPG22xPlus GPGVersion = 4
|
|
)
|
|
|
|
// GPGFinder implement search for gpg executables and returns version of discovered executables
|
|
type GPGFinder interface {
|
|
FindGPG() (gpg string, version GPGVersion, err error)
|
|
FindGPGV() (gpgv string, version GPGVersion, err error)
|
|
}
|
|
|
|
type pathGPGFinder struct {
|
|
gpgNames []string
|
|
gpgvNames []string
|
|
errorMessage string
|
|
|
|
expectedVersionSubstring string
|
|
}
|
|
|
|
type iteratingGPGFinder struct {
|
|
finders []GPGFinder
|
|
errorMessage string
|
|
}
|
|
|
|
// GPGDefaultFinder looks for GPG1 first, but falls back to GPG2 if GPG1 is not available
|
|
func GPGDefaultFinder() GPGFinder {
|
|
return &iteratingGPGFinder{
|
|
finders: []GPGFinder{GPG1Finder(), GPG2Finder()},
|
|
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg is installed",
|
|
}
|
|
}
|
|
|
|
// GPG1Finder looks for GnuPG1.x only
|
|
func GPG1Finder() GPGFinder {
|
|
return &pathGPGFinder{
|
|
gpgNames: []string{"gpg", "gpg1"},
|
|
gpgvNames: []string{"gpgv", "gpgv1"},
|
|
expectedVersionSubstring: `\(GnuPG.*\) (1).(\d)`,
|
|
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg1 is available as either gpg(v) or gpg(v)1 in $PATH",
|
|
}
|
|
}
|
|
|
|
// GPG2Finder looks for GnuPG2.x only
|
|
func GPG2Finder() GPGFinder {
|
|
return &pathGPGFinder{
|
|
gpgNames: []string{"gpg", "gpg2"},
|
|
gpgvNames: []string{"gpgv", "gpgv2"},
|
|
expectedVersionSubstring: `\(GnuPG.*\) (2).(\d)`,
|
|
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg2 is available as either gpg(v) or gpg(v)2 in $PATH",
|
|
}
|
|
}
|
|
|
|
func (pgf *pathGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) {
|
|
for _, cmd := range pgf.gpgNames {
|
|
var result bool
|
|
result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring)
|
|
if result {
|
|
gpg = cmd
|
|
break
|
|
}
|
|
}
|
|
|
|
if gpg == "" {
|
|
err = errors.New(pgf.errorMessage)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (pgf *pathGPGFinder) FindGPGV() (gpgv string, version GPGVersion, err error) {
|
|
for _, cmd := range pgf.gpgvNames {
|
|
var result bool
|
|
result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring)
|
|
if result {
|
|
gpgv = cmd
|
|
break
|
|
}
|
|
}
|
|
|
|
if gpgv == "" {
|
|
err = errors.New(pgf.errorMessage)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (it *iteratingGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) {
|
|
for _, finder := range it.finders {
|
|
gpg, version, err = finder.FindGPG()
|
|
if err == nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
err = errors.New(it.errorMessage)
|
|
|
|
return
|
|
}
|
|
|
|
func (it *iteratingGPGFinder) FindGPGV() (gpg string, version GPGVersion, err error) {
|
|
for _, finder := range it.finders {
|
|
gpg, version, err = finder.FindGPGV()
|
|
if err == nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
err = errors.New(it.errorMessage)
|
|
|
|
return
|
|
}
|
|
|
|
func cliVersionCheck(cmd string, marker string) (result bool, version GPGVersion) {
|
|
output, err := exec.Command(cmd, "--version").CombinedOutput()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
strOutput := string(output)
|
|
regex := regexp.MustCompile(marker)
|
|
|
|
version = GPG22xPlus
|
|
matches := regex.FindStringSubmatch(strOutput)
|
|
result = (matches != nil)
|
|
if matches != nil {
|
|
if matches[1] == "1" {
|
|
version = GPG1x
|
|
} else if matches[1] == "2" && matches[2] == "0" {
|
|
version = GPG20x
|
|
} else if matches[1] == "2" && matches[2] == "1" {
|
|
version = GPG21x
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|