Finding and retrieving Google Drive files with Go
Programming Snapshot – Go File Retrieval
Mike Schilli does not put books on the shelf; instead, he scans them and saves the PDFs in Google Drive. A command-line Go program then rummages through the digitized books and downloads them as required.
I have lots of PDFs of scanned books on my Google Drive and often download what I need from my digital bookshelf to my hard drive [1]. The browser interface on drive.google.com is very useful for this (Figure 1). However, Google Drive could be easier and faster to use when searching for books by listing the results and downloading matches immediately. The Go program presented in this issue does this at the command line, which goes down well with programmers who feel at home in the terminal window and are reluctant to ever leave it.
Building the source code from Listings 1 to 4 [2] and calling the generated binary that accepts a search string like algorithms-in-cpp
is shown in Figure 2. On the user's Google Drive, the program finds the PDF for the book Algorithms in C++. It offers up the file for selection and downloads it after confirmation. While the PDF, which is around 150MB in size, is crossing the wire, the Go program displays a slow or fast progress bar, depending on the Internet connection, to give an impression on the number of bytes received in relation to the expected total number.
Owners Only
Of course, I don't let every Tom, Dick, or Harry have access to my treasured and paid-for books. Therefore, a newly written client like the gd
program shown in Listing 1 first has to identify itself to Google Drive as personally authorized by me. This is not done by means of a username and password, but rather by following an OAuth 2 flow and then by means of access tokens, which the client can renew from locally cached refresh tokens after the former have expired.
Listing 1
gd.go
01 package main 02 03 import ( 04 "flag" 05 "fmt" 06 "golang.org/x/oauth2/google" 07 "google.golang.org/api/drive/v3" 08 "io/ioutil" 09 "log" 10 "os" 11 ) 12 13 func main() { 14 flag.Parse() 15 if flag.NArg() != 1 { 16 log.Fatalf(fmt.Sprintf("usage: %s partial-name", os.Args[0])) 17 } 18 query := flag.Arg(0) 19 20 b, err := ioutil.ReadFile("credentials.json") 21 if err != nil { 22 log.Fatalf("Error reading client secret file: %v", err) 23 } 24 config, err := google.ConfigFromJSON(b, drive.DriveReadonlyScope) 25 if err != nil { 26 log.Fatalf("Error parsing config: %v", err) 27 } 28 29 client := oauth2Client(config) 30 srv, err := drive.New(client) 31 if err != nil { 32 log.Fatalf("Error retrieving gdrive client: %v", err) 33 } 34 35 err = pickNGet(srv, query) 36 if err != nil { 37 log.Fatalf("Error retrieving document: %v", err) 38 } 39 }
The main program in Listing 1 uses the flag package to read the search term from the command line; the pattern provided by the user needs to match one or more files in Google Drive. In the version shown in this issue, the program searches for matches with file names. A full-text search would also be possible with a minor change to the source code.
Before sending the user through the OAuth 2 flow, line 20 parses the credentials.json
file, which defines the client secrets (i.e., the data with which Google identifies the application – the Go program, not the user). The user's consent is later obtained by a browser dialog, started by the user by cutting and pasting a URL produced by the Go program, when started for the first time. Equipped with valid credentials, pickNGet()
in line 35 then sets out to offer up the user documents that match the search term and downloads them upon request.
What the client is ultimately allowed to do after the user has given their permission is determined by the so-called OAuth scope, which developers set in their applications in advance and tell Google when they register the application. When the user later agrees to let the client have access, Google displays the scope to make sure the user knows what's at stake. Possible scope values range from access to meta-information of the files stored on the drive to actual reading and download rights, up to unlimited write access. Listing 1 defines DriveReadonlyScope
for the Go program; this allows the client to query the file names and download the content in question.
Second-Class Citizen Go
While the developer pages for the Google Drive API show examples in Java, Python, and Node.js (Figure 3), Google doesn't seem to consider Go to be a first-class citizen.
I was rubbing my eyes in disbelief, while scrolling through auto-generated spaghetti code, having to reverse engineer how to call the API functions with their correct signatures. On Stack Overflow, you will find five-year-old requests from perplexed programmers, and only a few brave developers have ever found an answer to handling even the most trivial of tasks.
Of course, you could also access the web API directly in Go, but if Google already provides an SDK, then they should document it and maintain it to keep it up-to-date.
OAuth, Take Two
So where does the credentials.json
file come from? It is the result of the developer registering the client program with Google as an API application. On the Developers Console for the Google API [3], you first need to enable the Google Drive API with a valid Google account (Figure 4). On the same page, you then have to register the Go client as a desktop application and define how it will be represented later when Google asks the user whether they want to grant the app access to their Google Drive data.
Google lets you download the registration data in JSON format under the file name client-secret*
(Figure 5), but you should rename it, because the client in Listing 1 expects the data as credentials.json
. Keep in mind though that the app is not given access to user data on the basis of these credentials yet; instead, it's only for registration purposes of the app with Google.
When the Go program is later launched for the first time, it finds the JSON credentials file in the same directory and prints a link to standard output (Figure 6), which the end user is instructed to copy into the URL field of a web browser before being directed to the OAuth 2 flow.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.