github.com/artpar/rclone@v1.67.3/bin/resource_windows.go (about)

     1  // Utility program to generate Rclone-specific Windows resource system object
     2  // file (.syso), that can be picked up by a following go build for embedding
     3  // version information and icon resources into a rclone binary.
     4  //
     5  // Run it with "go generate", or "go run" to be able to customize with
     6  // command-line flags. Note that this program is intended to be run directly
     7  // from its original location in the source tree: Default paths are absolute
     8  // within the current source tree, which is convenient because it makes it
     9  // oblivious to the working directory, and it gives identical result whether
    10  // run by "go generate" or "go run", but it will not make sense if this
    11  // program's source is moved out from the source tree.
    12  //
    13  // Can be used for rclone.exe (default), and other binaries such as
    14  // librclone.dll (must be specified with flag -binary).
    15  //
    16  
    17  //go:generate go run resource_windows.go
    18  //go:build tools
    19  
    20  package main
    21  
    22  import (
    23  	"flag"
    24  	"fmt"
    25  	"log"
    26  	"path"
    27  	"runtime"
    28  	"strings"
    29  
    30  	"github.com/artpar/rclone/fs"
    31  	"github.com/coreos/go-semver/semver"
    32  	"github.com/josephspurrier/goversioninfo"
    33  )
    34  
    35  func main() {
    36  	// Get path of directory containing the current source file to use for absolute path references within the code tree (as described above)
    37  	projectDir := ""
    38  	_, sourceFile, _, ok := runtime.Caller(0)
    39  	if ok {
    40  		projectDir = path.Dir(path.Dir(sourceFile)) // Root of the current project working directory
    41  	}
    42  
    43  	// Define flags
    44  	binary := flag.String("binary", "rclone.exe", `The name of the binary to generate resource for, e.g. "rclone.exe" or "librclone.dll"`)
    45  	arch := flag.String("arch", runtime.GOARCH, `Architecture of resource file, or the target GOARCH, "386", "amd64", "arm", or "arm64"`)
    46  	version := flag.String("version", fs.Version, "Version number or tag name")
    47  	icon := flag.String("icon", path.Join(projectDir, "graphics/logo/ico/logo_symbol_color.ico"), "Path to icon file to embed in an .exe binary")
    48  	dir := flag.String("dir", projectDir, "Path to output directory where to write the resulting system object file (.syso), with a default name according to -arch (resource_windows_<arch>.syso), only considered if not -syso is specified")
    49  	syso := flag.String("syso", "", "Path to output resource system object file (.syso) to be created/overwritten, ignores -dir")
    50  
    51  	// Parse command-line flags
    52  	flag.Parse()
    53  
    54  	// Handle default value for -file which depends on optional -dir and -arch
    55  	if *syso == "" {
    56  		// Use default filename, which includes target GOOS (hardcoded "windows")
    57  		// and GOARCH (from argument -arch) as suffix, to avoid any race conditions,
    58  		// and also this will be recognized by go build when it is consuming the
    59  		// .syso file and will only be used for builds with matching os/arch.
    60  		*syso = path.Join(*dir, fmt.Sprintf("resource_windows_%s.syso", *arch))
    61  	}
    62  
    63  	// Parse version/tag string argument as a SemVer
    64  	stringVersion := strings.TrimPrefix(*version, "v")
    65  	semanticVersion, err := semver.NewVersion(stringVersion)
    66  	if err != nil {
    67  		log.Fatalf("Invalid version number: %v", err)
    68  	}
    69  
    70  	// Extract binary extension
    71  	binaryExt := path.Ext(*binary)
    72  
    73  	// Create the version info configuration container
    74  	vi := &goversioninfo.VersionInfo{}
    75  
    76  	// FixedFileInfo
    77  	vi.FixedFileInfo.FileOS = "040004" // VOS_NT_WINDOWS32
    78  	if strings.EqualFold(binaryExt, ".exe") {
    79  		vi.FixedFileInfo.FileType = "01" // VFT_APP
    80  	} else if strings.EqualFold(binaryExt, ".dll") {
    81  		vi.FixedFileInfo.FileType = "02" // VFT_DLL
    82  	} else {
    83  		log.Fatalf("Specified binary must have extension .exe or .dll")
    84  	}
    85  	// FixedFileInfo.FileVersion
    86  	vi.FixedFileInfo.FileVersion.Major = int(semanticVersion.Major)
    87  	vi.FixedFileInfo.FileVersion.Minor = int(semanticVersion.Minor)
    88  	vi.FixedFileInfo.FileVersion.Patch = int(semanticVersion.Patch)
    89  	vi.FixedFileInfo.FileVersion.Build = 0
    90  	// FixedFileInfo.ProductVersion
    91  	vi.FixedFileInfo.ProductVersion.Major = int(semanticVersion.Major)
    92  	vi.FixedFileInfo.ProductVersion.Minor = int(semanticVersion.Minor)
    93  	vi.FixedFileInfo.ProductVersion.Patch = int(semanticVersion.Patch)
    94  	vi.FixedFileInfo.ProductVersion.Build = 0
    95  
    96  	// StringFileInfo
    97  	vi.StringFileInfo.CompanyName = "https://rclone.org"
    98  	vi.StringFileInfo.ProductName = "Rclone"
    99  	vi.StringFileInfo.FileDescription = "Rclone"
   100  	vi.StringFileInfo.InternalName = (*binary)[:len(*binary)-len(binaryExt)]
   101  	vi.StringFileInfo.OriginalFilename = *binary
   102  	vi.StringFileInfo.LegalCopyright = "The Rclone Authors"
   103  	vi.StringFileInfo.FileVersion = stringVersion
   104  	vi.StringFileInfo.ProductVersion = stringVersion
   105  
   106  	// Icon (only relevant for .exe, not .dll)
   107  	if *icon != "" && strings.EqualFold(binaryExt, ".exe") {
   108  		vi.IconPath = *icon
   109  	}
   110  
   111  	// Build native structures from the configuration data
   112  	vi.Build()
   113  
   114  	// Write the native structures as binary data to a buffer
   115  	vi.Walk()
   116  
   117  	// Write the binary data buffer to file
   118  	if err := vi.WriteSyso(*syso, *arch); err != nil {
   119  		log.Fatalf(`Failed to generate Windows %s resource system object file for %v with path "%v": %v`, *arch, *binary, *syso, err)
   120  	}
   121  }