How to handle case sensitive import collisions - go

I am using a third party library in GoLang that has previously had import paths in different case. Initially a letter was lower case then the author changed it to uppercase.
Some plugin authors updated their libraries and others didn't. In the meantime the original library author reverted the case change.
Now I find myself in a state where my application won't build due to to case import collisions.
How can one go about fixing this?
Many thanks

You could vendor the dependencies, and then go into the vendor/ directory and manually change (try greping or seding the dependency), the dependencies.
For an introduction to vendoring, try here, https://blog.gopheracademy.com/advent-2015/vendor-folder/
The original repo can still live in your GOPATH, but the 'corrected' version can go in the vendor folder, in which the compiler will look first when linking dependencies.
There are many tools for vendoring, I use govendor
Edit
As mkopriva mentions in the comments, you can refactor import names using the gofmt tool:
gofmt -w -r '"path/to/PackageName" -> "path/to/packagename"' ./
gofmt -w -r 'PackageName.x -> packagename.x' ./
The lowercase single character identifier is a wildcard.
from the docs
The rewrite rule specified with the -r flag must be a string of the form:
pattern -> replacement
Both pattern and replacement must be valid Go expressions. In the pattern, single-character lowercase identifiers serve as wildcards matching arbitrary sub-expressions; those expressions will be substituted for the same identifiers in the replacement.

Just if anyone wonders why this error might occur in your project: Make sure all imports use either lowercase or uppercase path, but not mixed.
So like this:
one.go -> "github.com/name/app/login"
another.go -> "github.com/name/app/login"
And not like this:
one.go -> "github.com/name/app/Login"
another.go -> "github.com/name/app/login"

Related

School me on Go packages, imports and protos

I'm mostly familiar with Python and a bazel build environment. I'm trying to rewrite a portion of code in Go and I'm struggling to get the proto imports to align properly.
In github.com/djhedges/exit_speed/gps.proto I have set go_package like so
option go_package = "github.com/djhedges/exit_speed/gps_go_proto";
I've added a reflector.proto which imports gps.proto and reuses some of the messages defined in there.
import "gps.proto";
I compile gps.proto with
protoc -I ./ --go_out=./ --go_opt=paths=source_relative --python_out ./ gps.proto
And compile reflector.proto with
LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1 python3 -m grpc_tools.protoc -I ./ --go_out=./ --go_opt=paths=source_relative --python_out ./ --grpc_python_out ./ reflector.proto
And finally in exit_speed/reflector.go I try to import gps_go_proto with
import gpspb "github.com/djhedges/exit_speed/gps_go_proto"
Which errors with
go: finding github.com/djhedges/exit_speed/gps_go_proto latest
reflector.go:21:2: unknown import path "github.com/djhedges/exit_speed/gps_go_proto": cannot find module providing package github.com/djhedges/exit_speed/gps_go_proto
I would prefer to keep gps.proto in the root directory if possible because I have protos logged into data files and I believe moving this breaks the proto parsing. I suppose I could write a migration script.
I'm also confused as to how setup multiple protos with different go packages and imports. Do go packages have to have a dedicated folder?
If I'm understanding go packages correctly the package name must map to a directory. By changing --go_out=./ to --go_out=./gps_go_proto seems to solve my issue without having to move the proto files. It does mean I have some additional directories but that seems okay.
As the Go Specification import section says:
Import declarations
An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported.
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
(snipped here, and I broke some links; use the first link to get the text with the links). The string literal is the familiar:
import "github.com/..."
part; the PackageName, or a dot, are optional. Returning to the text:
The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.
In your own answer, you add:
If I'm understanding go packages correctly the package name must map to a directory.
That's not necessarily so. It's up to the implementation to decide what the string literal means. In general, though, the Go build system will find a directory full of files, using this path. It may also use a version control system, such as Git, to fill a directory full of files, so that the compiler can find them.
Something that I found a bit surprising, but in the end, makes perfect sense (and is described in the spec), is this: the package name found in the package clause:
package somename
statement at the top of some imported file, is sometimes irrelevant. A directory full of files that implement package x will have them all say package x, of course. But it's the y identifier in the line:
import y "path/to/x"
in your package that supplies the name you use to access exported identifiers. The name you use here, with the import having y as the package name, is y, even if the package itself says package x. The package clause in package x is, in effect, just recommending the name x, so that you can write:
import "path/to/x"
if you'd like to refer to these as x.Thing.
There's no need for the string literal to mention x either: perhaps all the files are in something found via path/to/z, and you write:
import "path/to/z"
and then (still) write x.Thing because files in path/to/z/*.go recommend x as the package name.
How protoc uses this
Regardless of the above, the protobuf Go generators will print, in the generated name*.pb.go* Go code, an import directive. That import directive will read:
import "some/path/here"
You can specify the string literal using option go_package. The protobuf compiler doesn't need to interpret this itself. But, as the documentation notes, these name.pb.go files themselves will be dropped into a directory somewhere. They will also contain a package pkg line, of course.
The location of each output file depends on whether you use --go_opt=paths=source_relative. If you do, the go_package option string becomes irrelevant here.
The .pb.go file generator takes the go_package option string, strips off everything up to and including the last slash, and uses the remaining string for the package line.
The second point means that regardless of what the Go system itself does, how it finds these files, and how you write your own imports, the recommended package name in those files will be the last component of whatever was in the go_package option. So in a sense, all you really need is the final component. But if your Go implementation needs more than that, you can supply more.
The first point means that if you don't use --go_opt=paths=source_relative, the rest of the text in the go_package option matters: the Go generator will try to use that string to produce output files. So if your Go implementation needs more, and you do supply more, and it doesn't match what you want for output file names, you'll definitely need the --go-opt.

autoconf: how do I substitute the library prefix?

CLISP's interface to PARI is configured with the configure.in containing AC_LIB_LINKFLAGS([pari]) from lib-link.m4.
The build process also requires the Makefile to know where the datadir of PARI is located. To this end, Makefile.in has
prefix = #LIBPARI_PREFIX#
DATADIR = #datadir#
and expects to find $(DATADIR)/pari/pari.desc (normally
/usr/share/pari/pari.desc or /usr/local/share/pari/pari.desc).
This seems to work on Mac OS X where PARI is installed by homebrew in /usr/local (and LIBPARI_PREFIX=/usr/local), but not on Ubuntu, where PARI is in /usr, and LIBPARI_PREFIX is empty.
How do I insert the location of the PARI's datadir into the Makefile?
PS. I also asked this on the autoconf mailing list.
PPS. In response to #BrunoHaible's suggestion, here is the meager attempt at debugging on Linux (where LIBPARI_PREFIX is empty).
$ bash -x configure 2>&1 | grep found_dir
+ found_dir=
+ eval ac_val=$found_dir
+ eval ac_val=$found_dir
You are trying to use $(prefix) in an unintended way. In an Autotools-based build system, the $(prefix) represents a prefix to the target installation location of the software you're building. By setting it in your Makefile.in, you are overriding the prefix that configure will try to assign. However, since you appear not to have any installation targets anyway, at least at that level, that's probably more an issue of poor form than a cause for malfunction.
How do I insert the location of the PARI's datadir into the Makefile?
I'd recommend computing or discovering the needed directory in your configure script, and exporting it to the generated Makefile via its own output variable. Let's take the second part first, since it's simple. In configure.in, having in some manner located the wanted data directory and assigned it to a variable
DATADIR=...
, you would make an output variable of that via the AC_SUBST macro:
AC_SUBST([DATADIR])
Since you are using only Autoconf, not Automake, you would then manually receive that into your Makefile by changing the assignment in your Makefile.in:
DATDIR = #DATADIR#
Now, as for locating the data directory in the first place, you have to know what you're trying to implement before you can implement it. From your question and followup comments, it seems to me that you want this:
Use a data directory explicitly specified by the user if there is one. Otherwise,
look for a data directory relative to the location of the shared library. If it's not found there then
(optional) look under the prefix specified to configure, or specifically in the specified datadir (both of which may come from the top-level configure). Finally, if it still has not been found then
look in some standard locations.
To create a configure option by which the user can specify a custom data directory, you would probably use the AC_ARG_WITH macro, maybe like this:
AC_ARG_WITH([pari-datadir], [AS_HELP_STRING([--with-pari-datadir],
[explicitly specifies the PARI data directory])],
[], [with_pari_datadir=''])
Thanks to #BrunoHaible, we see that although the Gnulib manual does not document it, the macro's internal documentation specifies that if AC_LIB_LINKFLAGS locates libpari then it will set LIBPARI_PREFIX to the library directory prefix. You find that that does work when the --with-libpari option is used to give it an alternative location to search, so I suggest working with that. You certainly can try to debug AC_LIB_LINKFLAGS to make it set LIBPARI_PREFIX in all cases in which the lib is found, but if you don't want to go to that effort then you can work around it (see below).
Although the default or specified installation prefix is accessible in configure as $prefix, I would suggest instead going to the specified $datadir. That is slightly tricky, however, because by default it refers to the prefix indirectly. Thus, you might do this:
eval "datadir_expanded=${datadir}"
Finally, you might hardcode a set of prefixes such as /usr and /usr/local.
Following on from all the foregoing, then, your configure.in might do something like this:
DATADIR=
for d in \
${with_pari_datadir} \
${LIBPARI_PREFIX:+${LIBPARI_PREFIX}/share/pari} \
${datadir_expanded}/pari \
/usr/local/share/pari \
/usr/share/pari
do
AS_IF([test -r "$[]d/pari.desc"], [DATADIR="$[]d"; break])
done
AS_IF([test x = "x$DATADIR"], [AC_MSG_ERROR(["Could not identify PARI data directory"])])
AC_SUBST([DATADIR])
Instead of guessing the location of datadir, why don't you ask PARI/GP where its datadir is located? Namely,
$ echo "default(datadir)" | gp -qf
"/usr/share/pari"
does the trick.

Can ack be coerced into searching a complicated project

ack is a great tool for searching, especially if everything you want to find is in nested directories below a top project dir.
I'd like to search a number of different directory trees, in order to search my whole project.
I could do something like this (there are 5 or 6 more directories I'd include):
ack sometext . ../../Libraries/CMSIS/Device/ST/STM32F4xx/ ../../Libraries/CMSIS/
I've also tried doing it via the makefile, where I'd make ack a phony target, invoking ack on the directories Makefile knows about. This works, but the syntax to invoke it is unfortunate:
gmake ack SVAL=sometext
where in the Makefile:
ack:
$(ACK) $(SVAL) $(LIB_DIRS) $(DEVICE_DIRS) $(OTHER_PROJECT_DIRS)
Ideally, there would be something I could embed in the .ackrc to define the directories that ack searches. Anyone have a favorite way to use ack to search a complicated project directory structure?
Since ack can do what I want, with a complicated command line. My best answer to date is to embed it in a bash script, so I would type:
./pack foobar
To search my entire project for foobar.
The script pack would look like this:
#!/bin/bash
CONTEXT=-C1
c:/bin/ack $CONTEXT $* . ../../Libraries/CMSIS/Device/ST/STM32F4xx/ \
../../Libraries/CMSIS/
Still would prefer a .ackrc solution.
Sack: wrapper for grep, ack and/or ag (silver searcher)
http://sampsonchen.com/sack/
Can switch your `search environment' using pre-set profiles, sets up the CL flags and preset target (MULTIPLE) top-level starting-point directorieS

Organizing asset files in a Go project

I have a project that contains a folder to manage file templates, but it doesn't look like Go provides any support for non-Go-code project files. The project itself compiles to an executable, but it needs to know where this template folder is in order to operate correctly. Right now I do a search for $GOPATH/src/<templates>/templates, but this feels like kind of a hack to me because it would break if I decided to rename the package or host it somewhere else.
I've done some searching and it looks like a number of people are interested in being able to "compile" the asset files by embedding them in the final binary, but I'm not sure how I feel about this approach.
Any ideas?
Either pick a path (or a list of paths) that users are expected to put the supporting data in (/usr/local/share/myapp, ...) or just compile it into the binary.
It depends on how you are planning to distribute the program. As a package? With an installer?
Most of my programs I enjoy just having a single file to deploy and I just have a few templates to include, so I do that.
I have an example using go-bindata where I build the html template with a Makefile, but if I build with the 'devel' flag it will read the file at runtime instead to make development easier.
I can think of two options, use a cwd flag, or infer from cwd and arg 0:
-cwd path/to/assets
path/to/exe -cwd=$(path/to/exe/assets)
Internally, the exectable would chdir to wherever cwd points to, and then it can use relative paths throughout the application. This has the added benefit that the user can change the assets without having to recompile the program.
I do this for config files. Basically the order goes:
process cmd arguments, looking for a -cwd variable (it defaults to empty)
chdir to -cwd
parse config file
reparse cmd arguments, overwriting the settings in the config file
I'm not sure how many arguments your app has, but I've found this to be very useful, especially since Go doesn't have a standard packaging tool that will compile these assets in.
infer from arg 0
Another option is to use the first argument and get the path to the executable. Something like this:
here := path.Dir(os.Args[0])
if !path.IsAbs(os.Args[0]) {
here = path.Join(os.Getwd(), here)
}
This will get you the path to where the executable is. If you're guaranteed the user won't move this without moving the rest of your assets, you can use this, but I find it much more flexible to use the above -cwd idea, because then the user can place the executable anywhere on their system and just point it to the assets.
The best option would probably be a mixture of the two. If the user doesn't supply a -cwd flag, they probably haven't moved anything, so infer from arg 0 and the cwd. The cwd flag overrides this.

xcode 4.5.1. Header Search path not working, <directory/file.h> file not found

I have added a include directory in my home directory. I can run "ls -l ~/include" from the build directory.
I have added that directory in both "Header Seach Path" and in "User Header Search Path". In both places I have tried with both non-recursive and recursive.
But xcode 4.5.1 can not in any situation find the first stated header file.
It is stated in source code calls.m as:
#include <directory/file.h>
I get a "Lexical or Preprocessor issue 'directory/file.h' file not found."
But when running xcodebuild from cli it has no problems what so ever to build the source.
I have tried many of the suggestions found on internet
Putting a include in /usr/ om my drive
Adding a index to the project, adding files with no copy and no "Add to target" marked.
Restart xcode.
Specifying all specific paths.
But still no go.
What is the problem. Bug´s in xcode?
I just had a similar issue, and it was because there were spaces in the path which I defined for the Header Search Path. For example, I was defining the following as a search path:
$(SRCROOT)/Frameworks/Headers
which was being expanded out to the following:
/Users/skoota/Documents/Xcode Projects/My App/Frameworks/Headers
as you can see, there are spaces within the path (which are not immediately evident, as you are using the $(SRCROOT) variable) and the compiler doesn't particularly appreciate the spaces. I solved this problem by changing the search path to this:
"$(SRCROOT)"/Frameworks/Headers
(note the quote marks around $(SRCROOT) which escapes the spaces). This now expanded out to:
"/Users/skoota/Documents/Xcode Projects/My App"/Frameworks/Headers
which works perfectly, although looks a bit odd with the embedded " marks. This took me a while to figure out, so hopefully it helps!
This usually happens if there are spaces in your directory's path. To overcome this problem, use double quotes around the path.
Suppose you want to use your project directory, then you should use: $PROJECT_DIR. Enable recursive if you want to search within the folders as well. Alternatively, you can use $(SRCROOT)

Resources