Reputation: 27
I have a python script that creates a Google Drive file via API and uploads it. I am trying to rewrite the script in Go but the API documentation does not provide a Go quickstart. Here is the python script:
#!/bin/python
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from apiclient.http import MediaFileUpload
try:
import argparse
parser = argparse.ArgumentParser(description='Ebay Google Drive Uploader')
parser.add_argument('-r', metavar="rack",
help="-r <rack>")
except ImportError:
parser = None
try:
args = parser.parse_args()
except:
print (parser.error)
#print ("parser = ", parser)
if not args.r:
print ("Please specify rack (-r rack)")
exit
else:
#print ("Processing ", args.r)
sheet_name = args.r + ".csv"
sheet_filename = '/tmp/' + args.r + '.csv'
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/drive-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Ebay Google Drive Uploader - [email protected]'
def get_credentials():
"""Gets valid user credentials from storage.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'drive-python-quickstart.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
print ("before flow\n")
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
print ("flow = ", flow)
flow.user_agent = APPLICATION_NAME
if parser:
credentials = tools.run_flow(flow, store, parser)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
"""Creates a spreadsheet using the Google Drive API
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('drive', 'v3', http=http)
file_metadata = {
'name' : sheet_name,
'mimeType' : 'application/vnd.google-apps.spreadsheet'
}
media = MediaFileUpload(sheet_filename,
mimetype='text/csv')
results = service.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
sheet_id = results["id"]
print (sheet_id)
#sheet_url = results["webViewLink"]
#print ('sheet_url = ', sheet_url)
def callback(request_id, response, exception):
if exception:
# Handle error
print (exception)
#else:
#print ("Permission Id: %s" % response.get('id'))
batch = service.new_batch_http_request(callback=callback)
domain_permission = {
'type': 'domain',
'role': 'writer',
'domain': 'ebay.com',
'allowFileDiscovery': True
}
batch.add(service.permissions().create(
fileId=sheet_id,
body=domain_permission,
fields='id',
))
batch.execute()
if __name__ == '__main__':
main()
The problem is that I can't figure out how to specify the media type. In Python I used MediaFileUpload but it looks like Golang requires a different method. Here's what I have in Go:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/user"
"path/filepath"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/drive/v3"
)
// getClient uses a Context and Config to retrieve a Token
// then generate a Client. It returns the generated Client.
func getClient(ctx context.Context, config *oauth2.Config) *http.Client {
cacheFile, err := tokenCacheFile()
if err != nil {
log.Fatalf("Unable to get path to cached credential file. %v", err)
}
tok, err := tokenFromFile(cacheFile)
if err != nil {
tok = getTokenFromWeb(config)
saveToken(cacheFile, tok)
}
return config.Client(ctx, tok)
}
// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
fmt.Printf("Go to the following link in your browser then type the "+
"authorization code: \n%v\n", authURL)
var code string
if _, err := fmt.Scan(&code); err != nil {
log.Fatalf("Unable to read authorization code %v", err)
}
tok, err := config.Exchange(oauth2.NoContext, code)
if err != nil {
log.Fatalf("Unable to retrieve token from web %v", err)
}
return tok
}
// tokenCacheFile generates credential file path/filename.
// It returns the generated credential path/filename.
func tokenCacheFile() (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
os.MkdirAll(tokenCacheDir, 0700)
return filepath.Join(tokenCacheDir,
url.QueryEscape("drive-go-quickstart.json")), err
}
// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func tokenFromFile(file string) (*oauth2.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := &oauth2.Token{}
err = json.NewDecoder(f).Decode(t)
defer f.Close()
return t, err
}
// saveToken uses a file path to create a file and store the
// token in it.
func saveToken(file string, token *oauth2.Token) {
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}
func main() {
ctx := context.Background()
b, err := ioutil.ReadFile("/usr/local/lib/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-go-quickstart.json
config, err := google.ConfigFromJSON(b, drive.DriveFileScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
srv, err := drive.New(client)
if err != nil {
log.Fatalf("Unable to retrieve drive Client %v", err)
}
file_metadata := make(map[string]string)
sheet_name := "SLC:SLC02:02-314:06:04.csv"
sheet_filename := "/tmp/SLC:SLC02:02-314:06:04.csv"
file_metadata["name"] = sheet_name
file_metadata["mimeType"] = "application/vnd.google-apps.spreadsheet"
media = MediaFileUpload(sheet_filename, mimetype="text/csv")
r, err := srv.Files.Create(body=file_metadata,
media_body=media,
fields='id')
if err != nil {
log.Fatalf("Unable to create file: %v", err)
}
}
Can someone provide a working example that creates and uploads a document to Google Drive?
Reference links are here: https://paste.fedoraproject.org/paste/JmElgduugSKLVSAYm1htGw
Upvotes: 2
Views: 4472
Reputation: 201713
How about this sample script? This sample was modified main()
of your script. When you use this sample, please replace your main()
to mine. In your Python script, it converts from CSV to Spreadsheet and modify the permissions. So also it gave the same flow to this sample.
options
of Media(r io.Reader, options ...googleapi.MediaOption)
.options
, use googleapi.ContentType()
.file
of Create(file *File)
.file
, use &drive.File{}
. &drive.Permission{}
. Each parameter is the same to them for Python.func main1() {
ctx := context.Background()
b, err := ioutil.ReadFile("/usr/local/lib/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-go-quickstart.json
config, err := google.ConfigFromJSON(b, drive.DriveFileScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
srv, err := drive.New(client)
if err != nil {
log.Fatalf("Unable to retrieve drive Client %v", err)
}
// I modified below.
sheet_name := "SLC:SLC02:02-314:06:04.csv" // File you want to upload on Google Drive
sheet_filename := "/tmp/SLC:SLC02:02-314:06:04.csv" // File you want to upload on your PC
baseMimeType := "text/csv" // mimeType of file you want to upload
convertedMimeType := "application/vnd.google-apps.spreadsheet" // mimeType of file you want to convert on Google Drive
file, err := os.Open(sheet_filename)
if err != nil {
log.Fatalf("Error: %v", err)
}
defer file.Close()
f := &drive.File{
Name: sheet_name,
MimeType: convertedMimeType,
}
res, err := srv.Files.Create(f).Media(file, googleapi.ContentType(baseMimeType)).Do()
if err != nil {
log.Fatalf("Error: %v", err)
}
fmt.Printf("%s, %s, %s\n", res.Name, res.Id, res.MimeType)
permissiondata := &drive.Permission{
Type: "domain",
Role: "writer",
Domain: "ebay.com",
AllowFileDiscovery: true,
}
pres, err := srv.Permissions.Create(res.Id, permissiondata).Do()
if err != nil {
log.Fatalf("Error: %v", err)
}
fmt.Printf("%s, %s\n", pres.Type, pres.Role)
}
SLC:SLC02:02-314:06:04.csv, ### file ID on Google Drive ###, application/vnd.google-apps.spreadsheet
domain, writer
Also I got the infomation for this sample from godoc and GitHub of google-api-go-client.
This uses Quickstart. In order to use this sample script, please do the Step 1 and Step 2.
Or your library may be required to update.
At this sample script, it works file using google-api-go-client/drive/v3/
of Sep 13, 2017.
Upvotes: 4