github.com/rgonomic/rgo@v0.2.2-0.20220708095818-4747f0905d6e/internal/rgo/info.go (about)

     1  // Copyright ©2019 The rgonomic 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  
     5  // Copyright 2019 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  package rgo
    10  
    11  import (
    12  	"context"
    13  	"flag"
    14  	"fmt"
    15  	"io"
    16  	"os"
    17  	"runtime/debug"
    18  )
    19  
    20  // version implements the version command.
    21  type version struct {
    22  	app *Application
    23  }
    24  
    25  func (v *version) Name() string      { return "version" }
    26  func (v *version) Usage() string     { return "" }
    27  func (v *version) ShortHelp() string { return "print the rgo version information" }
    28  func (v *version) DetailedHelp(f *flag.FlagSet) {
    29  	fmt.Fprint(f.Output(), ``)
    30  	f.PrintDefaults()
    31  }
    32  
    33  // Run prints rgo version information.
    34  func (v *version) Run(ctx context.Context, args ...string) error {
    35  	printBuildInfo(os.Stdout, v.app.Verbose)
    36  	return nil
    37  }
    38  
    39  func printBuildInfo(w io.Writer, verbose bool) {
    40  	if info, ok := debug.ReadBuildInfo(); ok {
    41  		fmt.Fprintf(w, "%v %v\n", info.Path, info.Main.Version)
    42  		if verbose {
    43  			for _, dep := range info.Deps {
    44  				printModuleInfo(w, dep)
    45  			}
    46  		}
    47  	} else {
    48  		fmt.Fprintf(w, "version unknown, built in $GOPATH mode\n")
    49  	}
    50  }
    51  
    52  func printModuleInfo(w io.Writer, m *debug.Module) {
    53  	fmt.Fprintf(w, "    %s@%s", m.Path, m.Version)
    54  	if m.Sum != "" {
    55  		fmt.Fprintf(w, " %s", m.Sum)
    56  	}
    57  	if m.Replace != nil {
    58  		fmt.Fprintf(w, " => %v", m.Replace.Path)
    59  	}
    60  	fmt.Fprintf(w, "\n")
    61  }
    62  
    63  // help implements the help command.
    64  type help struct{}
    65  
    66  func (*help) Name() string      { return "help" }
    67  func (*help) Usage() string     { return "" }
    68  func (*help) ShortHelp() string { return "output rgo help information" }
    69  func (*help) DetailedHelp(f *flag.FlagSet) {
    70  	fmt.Fprint(f.Output(), ``)
    71  	f.PrintDefaults()
    72  }
    73  
    74  // Run outputs the help text.
    75  func (*help) Run(ctx context.Context, args ...string) error {
    76  	fmt.Fprintf(os.Stdout, "%s", helpText)
    77  	return nil
    78  }
    79  
    80  // Keep this reasonably in sync with the README.md.
    81  const helpText = `
    82  Workflow
    83  
    84  Initialize the go package module.
    85  
    86  $ go mod init example.org/path/to/module
    87  
    88  Specify dependency versions using the go tool if needed.
    89  
    90  $ go get example.org/path/to/dependency@vX.Y.Z
    91  
    92  Set up the rgo default configurations and files.
    93  
    94  $ rgo init example.org/path/to/pkg
    95  
    96  Edit the configuration file, rgo.json, if needed. The rgo.json file
    97  corresponds to the following Go struct.
    98  
    99  type Config struct {
   100  	// PkgPath is the package import path for the package
   101  	// to be wrapped by rgo. It depends on the go.mod file
   102  	// at the root of the destination rgo package.
   103  	PkgPath string
   104  
   105  	// AllowedFuncs is a pattern matching names of
   106  	// functions that may be wrapped. If AllowedFuncs
   107  	// is empty all wrappable functions are wrapped.
   108  	AllowedFuncs string
   109  
   110  	// Words is a set of known words that can be provided
   111  	// to ensure camel-case to snake case breaks words
   112  	// correctly. If words is nil, "NaN" and "NA" are
   113  	// used. Set words to []string{} to provide an empty
   114  	// set of words.
   115  	Words []string
   116  
   117  	// LicenseDir is the directory to put license files
   118  	// when more than one license exists.
   119  	LicenseDir string
   120  
   121  	// LicensePattern is the pattern for license file
   122  	// names to check. The pattern is used with the
   123  	// case-insensitive flag.
   124  	LicensePattern string
   125  }
   126  
   127  Generate the wrapper code, documentation and other associated files.
   128  
   129  $ rgo build
   130  
   131  Make necessary changes to the DESCRIPTION file.
   132  If the R package is intended to be packaged license information for
   133  dependencies of the Go code will need to be included since Go links
   134  statically and the generated .so lib file will be part of the
   135  distribution. rgo build will collect all the licenses that it finds in
   136  the source module and place them in the LicenseDir directory. You should
   137  remove any that are not relevant to the package you are wrapping.
   138  
   139  Then package into a bundle for distribution and build and install the R
   140  package.
   141  
   142  $ R CMD INSTALL .
   143  
   144  
   145  Type mappings
   146  
   147  rgo has builtin type mappings between Go and R types. See the project
   148  README for the details of these.
   149  
   150  
   151  Go struct tags
   152  
   153  Go struct tags with the name rgo may be used to change the R value's
   154  name mapping. For example,
   155  
   156  type GoType struct {
   157  	Count int ` + "`rgo:\"number\"`" + `
   158  }
   159  
   160  will correspond to an R list with a single named element "number".
   161  
   162  
   163  Multiple return values
   164  
   165  Go functions returning multiple values will have these values packaged
   166  into a list with elements named for the return values in the case of Go
   167  functions named returns, or 'r<n>' for unnamed returns where '<n>' is
   168  the index of the return value.
   169  
   170  
   171  Panics
   172  
   173  Go panics are recovered and result in an R error call.
   174  
   175  
   176  Limitations
   177  
   178  R and Go have differences in indexing; R is one-based and Go is
   179  zero-based. This means that care needs to be taken when using indexes
   180  generated in the other environment.
   181  
   182  R lacks 64-bit integers, so rgo will refuse to wrap functions that have
   183  64-bit integer inputs or results (int64 and uint64). It also refuses to
   184  wrap function that take or return uintptr values. On Go architectures
   185  with 64-bit int and uint types, results are truncated to 32 bits. This
   186  behaviour will not change until R gets 64-bit integer types.
   187  
   188  R Matrix values are not currently handled and will need to be
   189  destructured to a vector and a pair of dimensions (see the example in
   190  examples/cca in the project repo for how to do this).
   191  
   192  Currently the extraction of type identities is weaker than it should be.
   193  This will be improved.
   194  
   195  Data exchange between R and Go depends on Cgo calls and so is not free.
   196  The exact performance impact depends on the type due to R's baroque type
   197  system and its implementation; briefly though, R vectors that have a
   198  direct correspondence with Go scalar types or slices will perform the
   199  best (integer and int32/uint32, double and float64, complex and
   200  complex128, and raw and int8/uint8). To check the likely performance of
   201  data exchange, look at the generated Go code in the src/rgo directory of
   202  the package you are building. The generated code is intended to be
   203  reasonably human readable.
   204  
   205  
   206  Input parameter mutation
   207  
   208  For types that have direct memory layout equivalents between Go and R
   209  (raw and []int8/[]uint8, integer and []int32/[]uint32, double/float64,
   210  and complex and []complex128) the vector is passed directly to Go. This
   211  means that the Go code can mutate elements. This needs to be considered
   212  when writing Go code that works on slices to avoid unwanted mutation of
   213  R values that are passed to Go. It can also be used for allocation free
   214  work on R vectors. Values passed back to R from Go are copied to satisfy
   215  Go's runtime restrictions on pointer passing.
   216  `