main.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // mkpkg builds the Tailscale rpm and deb packages.
  5. package main
  6. import (
  7. "fmt"
  8. "log"
  9. "os"
  10. "strings"
  11. "github.com/goreleaser/nfpm"
  12. _ "github.com/goreleaser/nfpm/deb"
  13. _ "github.com/goreleaser/nfpm/rpm"
  14. "github.com/pborman/getopt"
  15. )
  16. // parseFiles parses a comma-separated list of colon-separated pairs
  17. // into a map of filePathOnDisk -> filePathInPackage.
  18. func parseFiles(s string) (map[string]string, error) {
  19. ret := map[string]string{}
  20. if len(s) == 0 {
  21. return ret, nil
  22. }
  23. for _, f := range strings.Split(s, ",") {
  24. fs := strings.Split(f, ":")
  25. if len(fs) != 2 {
  26. return nil, fmt.Errorf("unparseable file field %q", f)
  27. }
  28. ret[fs[0]] = fs[1]
  29. }
  30. return ret, nil
  31. }
  32. func parseEmptyDirs(s string) []string {
  33. // strings.Split("", ",") would return []string{""}, which is not suitable:
  34. // this would create an empty dir record with path "", breaking the package
  35. if s == "" {
  36. return nil
  37. }
  38. return strings.Split(s, ",")
  39. }
  40. func main() {
  41. out := getopt.StringLong("out", 'o', "", "output file to write")
  42. goarch := getopt.StringLong("arch", 'a', "amd64", "GOARCH this package is for")
  43. pkgType := getopt.StringLong("type", 't', "deb", "type of package to build (deb or rpm)")
  44. files := getopt.StringLong("files", 'F', "", "comma-separated list of files in src:dst form")
  45. configFiles := getopt.StringLong("configs", 'C', "", "like --files, but for files marked as user-editable config files")
  46. emptyDirs := getopt.StringLong("emptydirs", 'E', "", "comma-separated list of empty directories")
  47. version := getopt.StringLong("version", 0, "0.0.0", "version of the package")
  48. postinst := getopt.StringLong("postinst", 0, "", "debian postinst script path")
  49. prerm := getopt.StringLong("prerm", 0, "", "debian prerm script path")
  50. postrm := getopt.StringLong("postrm", 0, "", "debian postrm script path")
  51. replaces := getopt.StringLong("replaces", 0, "", "package which this package replaces, if any")
  52. depends := getopt.StringLong("depends", 0, "", "comma-separated list of packages this package depends on")
  53. getopt.Parse()
  54. filesMap, err := parseFiles(*files)
  55. if err != nil {
  56. log.Fatalf("Parsing --files: %v", err)
  57. }
  58. configsMap, err := parseFiles(*configFiles)
  59. if err != nil {
  60. log.Fatalf("Parsing --configs: %v", err)
  61. }
  62. emptyDirList := parseEmptyDirs(*emptyDirs)
  63. info := nfpm.WithDefaults(&nfpm.Info{
  64. Name: "tailscale",
  65. Arch: *goarch,
  66. Platform: "linux",
  67. Version: *version,
  68. Maintainer: "Tailscale Inc <[email protected]>",
  69. Description: "The easiest, most secure, cross platform way to use WireGuard + oauth2 + 2FA/SSO",
  70. Homepage: "https://www.tailscale.com",
  71. License: "MIT",
  72. Overridables: nfpm.Overridables{
  73. EmptyFolders: emptyDirList,
  74. Files: filesMap,
  75. ConfigFiles: configsMap,
  76. Scripts: nfpm.Scripts{
  77. PostInstall: *postinst,
  78. PreRemove: *prerm,
  79. PostRemove: *postrm,
  80. },
  81. },
  82. })
  83. if len(*depends) != 0 {
  84. info.Overridables.Depends = strings.Split(*depends, ",")
  85. }
  86. if *replaces != "" {
  87. info.Overridables.Replaces = []string{*replaces}
  88. info.Overridables.Conflicts = []string{*replaces}
  89. }
  90. switch *pkgType {
  91. case "deb":
  92. info.Section = "net"
  93. info.Priority = "extra"
  94. case "rpm":
  95. info.Overridables.RPM.Group = "Network"
  96. }
  97. pkg, err := nfpm.Get(*pkgType)
  98. if err != nil {
  99. log.Fatalf("Getting packager for %q: %v", *pkgType, err)
  100. }
  101. f, err := os.Create(*out)
  102. if err != nil {
  103. log.Fatalf("Creating output file %q: %v", *out, err)
  104. }
  105. defer f.Close()
  106. if err := pkg.Package(info, f); err != nil {
  107. log.Fatalf("Creating package %q: %v", *out, err)
  108. }
  109. }