Passing flag variable to go program causing strange output - parsing

sergiotapia at Macbook-Air in ~/Work/go/src/github.com/sergiotapia/gophers on master [!]
$ go build && go install && gophers -github_url=https://github.com/search?utf8=%E2%9C%93&q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100&type=Users&ref=advsearch&l=
[1] 51873
[2] 51874
[3] 51875
[4] 51877
[2] Done q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100
[3] Done type=Users
[4]+ Done ref=advsearch
I'm trying to use the long github url as a parameter in my code for Gophers. It works fine for all other url types such as organisations or stargazers. However when I try to use the search results page I get the strange output above.
https://github.com/search?utf8=%E2%9C%93&q=location%3A%22San+Fransisco%22+location%3ACA+followers%3A%3E100&type=Users&ref=advsearch&l=
package main
import (
"flag"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
type user struct {
name string
email string
url string
username string
}
func main() {
url := flag.String("github_url", "", "github url you want to scrape")
flag.Parse()
githubURL := *url
doc, err := goquery.NewDocument(githubURL)
if err != nil {
log.Fatal(err)
}
if strings.Contains(githubURL, "/orgs/") {
scrapeOrganization(doc, githubURL)
} else if strings.Contains(githubURL, "/search?") {
scrapeSearch(doc, githubURL)
} else if strings.Contains(githubURL, "/stargazers") {
scrapeStarGazers(doc, githubURL)
} else {
scrapeProfile(doc)
}
}

It's a bash command line (or whatever the mac uses). & and ? are shell metacharacters that you MUST escape. The shell has absolutely no idea what a URL is, nor should it ever have to.
go 'http://....'
^-----------^
Adding quotes will prevent the shell from parsing the metacharacters. The alternative is to manually escape each and ever metachar yourself:
go http://example.com/script.php\?foo=bar\&baz=qux
^--------^
which quickly gets tedious, and error prone.

Related

How to extract list of docker images inside GCP artifact registry

I want to list all the repositories inside GCP artifact registry in golang.
Current code : (https://pkg.go.dev/cloud.google.com/go/artifactregistry/apiv1beta2)
c, err := artifactregistry.NewClient(ctx, option.WithCredentialsFile("<service account json>"))
if err != nil {
// no error here
}
defer c.Close()
req := &artifactregistrypb.ListRepositoriesRequest{
Parent: "<project-id>",
}
it := c.ListRepositories(ctx, req)
for {
resp, err := it.Next()
if err == nil {
fmt.Println("resp", resp)
} else {
fmt.Println("err ==>", err)
}
}
The error prints: Invalid field value in the request. OR sometimes I get Request contains an invalid argument
What am I doing wrong here ? and What does the "Parent" mean ? (in ListRepositoriesRequest)
On further digging, I found that the value passed in the Parent goes to : "x-goog-request-params", what should be the correct format for this ?
Sometime the libraries/api are well documented, sometime not...
Here the REST API that you can test in the API explorer (right hand side bar). After some tests, the parent must have that format
projects/<PROJECT_ID>/locations/<REGION>
Try with that to solve your issue

Why can't we make a good comparison? ruby-ffi call golang(so files)

I'm calling shared files created by Golang from ruby-ffi.
However, when I run Golang alone, the process works, but when I run it via ruby-ffi, the comparison doesn't work.
package main
import (
"C"
"fmt"
)
//export zen_roma_to_han_roma
func zen_roma_to_han_roma(s string) string {
if s=="test" {
return "10"
}
return s
}
func main(){
fmt.Println(zen_roma_to_han_roma("test"))
}
$ go run replace.go
10
Here's an example of what can go wrong.
First, create a go build and load it.
go build -buildmode=c-shared -o replace.so replace.go
module Sample
extend FFI::Library
ffi_lib 'replace.so'
attach_function :zen_roma_to_han_roma, [:string], :string
end
[5] pry(main)> Sample.zen_roma_to_han_roma("test")
=> "test
I don't know the cause of this and I need your help.
Is there anything else I should try?
I am not a Golang programmer but still here is a quote from the FFI gem documentation
:string should be considered to be const char * and the Ruby string must not be changed as long as it’s accessed by the library. If the string buffer shall be modified from C or Ruby side, use :pointer and FFI::MemoryPointer instead.
So you should pass *C.char as an argument and return a value of the same type instead of string.
package main
import (
"C"
"fmt"
)
//export zen_roma_to_han_roma
func zen_roma_to_han_roma(s *C.char) *C.char {
test_string := C.GoString(s)
if test_string == "test" {
return C.CString("10")
}
return s
}
func main() {
fmt.Println(C.GoString(zen_roma_to_han_roma(C.CString("test"))))
}

What to check to catch error in a Process.run?

I’m trying to run keytool command with Process.run and if anything goes wrong I want to stop the program. I was checking stderr property of ProcessResult but it also writes it there if it is successfull. So what should I be checking to catch errors and stop the program?
await Process.run(
'keytool',
[
'-genkey',
'-v',
'-keystore',
'/Users/figengungor/key.jks',
'-keyalg',
'RSA',
'-keysize',
'2048',
'-validity',
'10000',
'-alias',
'key',
'-dname',
'cn=Unknown, ou=Unknown, o=Unknown, c=Unknown',
'-storepass',
'123456',
],)
.then((ProcessResult results) {
print('${results.stdout}');
if (results.stderr != null && results.stderr.toString().isNotEmpty) {
print('${results.stderr}');
print('EXIT CODE ${results.exitCode}');
exit(0);
}
print('Keystore file is generated at /Users/figengungor/key.jks');
});
I just checked exitCode. If it is not zero, then smt is wrong. But error message can be inside stdout or stderr. So I went like this:
if(results.exitCode!=0) {
print('STDOUT ${results.stdout}');
print('STDERR ${results.stderr}');
print('EXIT CODE ${results.exitCode}');
exit(1);
}

How to wrap exec.Command inside an io.Writer

I'm trying to compress a JPEG image in go using mozjpeg. Since it doesn't have official go binding, I think I'll just invoke its CLI to do the compression.
I try to model the usage after compress/gzip:
c := jpeg.NewCompresser(destFile)
_, err := io.Copy(c, srcFile)
Now the question is, how do I wrap the CLI inside Compresser so it can support this usage?
I tried something like this:
type Compresser struct {
cmd exec.Command
}
func NewCompressor(w io.Writer) *Compresser {
cmd := exec.Command("jpegtran", "-copy", "none")
cmd.Stdout = w
c := &Compresser{cmd}
return c
}
func (c *Compresser) Write(p []byte) (n int, err error) {
if c.cmd.Process == nil {
err = c.cmd.Start()
if err != nil {
return
}
}
// How do I write p into c.cmd.Stdin?
}
But couldn't finish it.
Also, a second question is, when do I shut down the command? How to shut down the command?
You should take a look at the Cmd.StdinPipe. There is an example in the documentation, which suits your case:
package main
import (
"fmt"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("cat")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
go func() {
defer stdin.Close()
io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
}()
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
}
In this case, CombinedOutput() executes your command, and the execution is finished, when there are no more bytes to read from out.
As per Kiril's answer, use the cmd.StdInPipe to pass on the data you receive to Write.
However, in terms of closing, I'd be tempted to implement io.Closer. This would make *Compresser automatically implement the io.WriteCloser interface.
I would use Close() as the notification that there is no more data to be sent and that the command should be terminated. Any non-zero exit code returned from the command that indicates failure could be caught and returned as an error.
I would be wary of using CombinedOutput() inside Write() in case you have a slow input stream. The utility could finish processing the input stream and be waiting for more data. This would be incorrectly detected as command completion and would result in an invalid output.
Remember, the Write method can be called an indeterminate number of times during IO operations.

stub.GetHistoryKeys() reporting GetHistoryKeys() function undefined. when tried go build on my Chaincode

I am new to Hyperledger .I am using docker to run Hyperledger. Pulled hyperledger/fabric-peer:latest from Docker hub and
able to run stub.CreateTable() ,stub.GetRows() , stub.InsertRows() and some other functions in my Chaincode. But when i tried to run
stub.GetHistoryKeys() or stub.GetCompositeKeys() ...etc in my chaincode
It's reporting an error
stub.GetHistoryForKey undefined (type shim.ChaincodeStubInterface has no field
or method GetHistoryForKey)
I found that in my interface.go file there are no such functions . Googled a lot but found nothing .Can anyone tell the correct hyperledger/fabric-peer image to pull so that the above functions can run in Chaincode.
Please download latest version of fabric image, (
hyperledger/fabric-peer x86_64-1.1.0 ). It can be downloaded from script mentioned on hyperledger official website (Install binary)=> (https://hyperledger-fabric.readthedocs.io/en/latest/install.html. Can't paste url due to stackover flow policy issue). Once you have it. Create a go code. Simply add one json record on one key add then try to add some change some field of json and again add to same key. Once you have done that, fire the below code for gethistory:=>
func (s *SmartContract) getAllTransactionForid(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
fmt.Println("getAllTransactionForNumber called")
id:= args[0]
resultsIterator, err := APIstub.GetHistoryForKey(id)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
// buffer is a JSON array containing historic values for the number
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON marble)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
if !bArrayMemberAlreadyWritten {
buffer.WriteString("No record found")
}
buffer.WriteString("]")
fmt.Printf("- getAllTransactionForNumber returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
If still in doubt, please revert. I will give you my whole source code to make it work. But I hope this will make your problem go away :-)
At last I am able to figure it out to get the hyperledger images to support my chaincode.

Resources