Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cmd/librarian/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,5 +187,21 @@ Usage:
version prints the librarian binary version and exits. The version is
embedded at build time and follows the conventions described at
https://go.dev/ref/mod#versions.

# Various debugging commands

Usage:

librarian debug [command]

# Print environment variables for the librarian command line interface.

Usage:

librarian debug env

env prints the librarian interpretation of the environment it is run in.
This includes the resolved LIBRARIAN_CACHE and LIBRARIAN_BIN paths,
as well as the language-specific tool installation directories.
*/
package main
79 changes: 79 additions & 0 deletions internal/librarian/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package librarian

import (
"context"
"fmt"
"io"
"strings"

"github.com/googleapis/librarian/internal/cache"
"github.com/googleapis/librarian/internal/librarian/golang"
"github.com/googleapis/librarian/internal/librarian/java"
"github.com/urfave/cli/v3"
)

// debugCommand returns the CLI command for librarian debugging tools.
func debugCommand() *cli.Command {
return &cli.Command{
Name: "debug",
Usage: "various debugging commands",
UsageText: "librarian debug [command]",
Commands: []*cli.Command{
envCommand(),
},
}
}

// envCommand returns the CLI command for printing the librarian environment.
func envCommand() *cli.Command {
return &cli.Command{
Name: "env",
Usage: "print environment variables for the librarian command line interface.",
UsageText: "librarian debug env",
Description: `env prints the librarian interpretation of the environment it is run in.
This includes the resolved LIBRARIAN_CACHE and LIBRARIAN_BIN paths,
as well as the language-specific tool installation directories.`,
Action: func(ctx context.Context, cmd *cli.Command) error {
return runEnv(cmd.Root().Writer)
},
}
}

func runEnv(w io.Writer) error {
cacheDir := dirOrErr(cache.Directory())
buildDir := dirOrErr(cache.BinDirectory())
goToolsDir := dirOrErr(golang.InstallDir())
javaToolsDir := dirOrErr(java.InstallDir())
var b strings.Builder
fmt.Fprintf(&b, "LIBRARIAN_CACHE=%s\n", cacheDir)
fmt.Fprintf(&b, "LIBRARIAN_BIN=%s\n", buildDir)
fmt.Fprintln(&b)
fmt.Fprintln(&b, "Language-specific tool installation directories:")
fmt.Fprintf(&b, " golang: %s\n", goToolsDir)
fmt.Fprintf(&b, " java: %s\n", javaToolsDir)
_, err := io.WriteString(w, b.String())
return err
}

// dirOrErr converts a directory path and potential error into a string. If an error
// occurred, it returns a formatted error string; otherwise, it returns the directory path.
func dirOrErr(dir string, err error) string {
if err != nil {
return fmt.Sprintf("<error: %v>", err)
}
return dir
}
70 changes: 70 additions & 0 deletions internal/librarian/debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package librarian

import (
"bytes"
"fmt"
"path/filepath"
"strings"
"testing"
)

func TestRunEnv(t *testing.T) {
cacheDir := t.TempDir()
binDir := t.TempDir()
t.Setenv("LIBRARIAN_CACHE", cacheDir)
t.Setenv("LIBRARIAN_BIN", binDir)
var buf bytes.Buffer
if err := runEnv(&buf); err != nil {
t.Fatal(err)
}
got := buf.String()
wants := []string{
fmt.Sprintf("LIBRARIAN_CACHE=%s", cacheDir),
fmt.Sprintf("LIBRARIAN_BIN=%s", binDir),
fmt.Sprintf("golang: %s", filepath.Join(binDir, "go_tools")),
fmt.Sprintf("java: %s", filepath.Join(binDir, "java_tools")),
}
for _, want := range wants {
if !strings.Contains(got, want) {
Comment thread
hj690 marked this conversation as resolved.
t.Errorf("runEnv() output missing %q\ngot:\n%s", want, got)
}
}
}

func TestRunEnv_Error(t *testing.T) {
// Unset environment variables to force path resolution errors.
t.Setenv("LIBRARIAN_CACHE", "")
t.Setenv("LIBRARIAN_BIN", "")
t.Setenv("HOME", "")
t.Setenv("XDG_CACHE_HOME", "")
var buf bytes.Buffer
if err := runEnv(&buf); err != nil {
t.Fatal(err)
}
got := buf.String()
wants := []string{
"LIBRARIAN_CACHE=<error:",
Comment thread
hj690 marked this conversation as resolved.
"LIBRARIAN_BIN=<error:",
"golang: <error:",
"java: <error:",
}
for _, want := range wants {
if !strings.Contains(got, want) {
t.Errorf("runEnv() output missing %q\ngot:\n%s", want, got)
}
}
}
2 changes: 1 addition & 1 deletion internal/librarian/golang/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func runInDirWithEnv(ctx context.Context, dir string, env map[string]string, cmd

// mergeEnv merges the given environment with the installation directory.
func mergeEnv(env map[string]string) (map[string]string, error) {
toolsBinDir, err := getInstallDir()
toolsBinDir, err := InstallDir()
if err != nil {
return nil, err
}
Expand Down
20 changes: 10 additions & 10 deletions internal/librarian/golang/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,17 @@ func Install(ctx context.Context, tools *config.Tools) error {
return installGoTools(ctx, tools.Go)
}

// InstallDir gets the directory where tools should be installed.
func InstallDir() (string, error) {
dir, err := cache.BinDirectory()
if err != nil {
return "", err
}
return filepath.Abs(filepath.Join(dir, toolsDir))
}

func installGoTools(ctx context.Context, goTools []*config.GoTool) error {
installDir, err := getInstallDir()
installDir, err := InstallDir()
if err != nil {
return err
}
Expand All @@ -62,12 +71,3 @@ func installGoTools(ctx context.Context, goTools []*config.GoTool) error {
}
return nil
}

// getInstallDir gets the directory where tools should be installed.
func getInstallDir() (string, error) {
dir, err := cache.BinDirectory()
if err != nil {
return "", err
}
return filepath.Abs(filepath.Join(dir, toolsDir))
}
2 changes: 1 addition & 1 deletion internal/librarian/golang/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func TestGetInstallDir(t *testing.T) {
for k, v := range test.env {
t.Setenv(k, v)
}
got, err := getInstallDir()
got, err := InstallDir()
if err != nil {
t.Fatal(err)
}
Expand Down
22 changes: 11 additions & 11 deletions internal/librarian/java/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ func Install(ctx context.Context, tools *config.Tools) error {
return nil
}

// InstallDir returns the absolute path of the installation directory for Java tools.
func InstallDir() (string, error) {
dir, err := cache.BinDirectory()
if err != nil {
return "", err
}
return filepath.Abs(filepath.Join(dir, toolsDir))
}

// installExternalMavenTool downloads a Maven-based external tool, copies its compiled artifact
// (.jar or .exe) to the sibling lib folder, and creates an executable wrapper script
// in the bin folder pointing directly to that library file.
Expand Down Expand Up @@ -233,18 +242,9 @@ func buildLocalMavenProject(ctx context.Context, localPath string) error {
return nil
}

// getInstallDir returns the absolute path of the installation directory for Java tools.
func getInstallDir() (string, error) {
dir, err := cache.BinDirectory()
if err != nil {
return "", err
}
return filepath.Abs(filepath.Join(dir, toolsDir))
}

// getBinDir returns the absolute path of the directory where Java tool wrapper scripts are stored.
func getBinDir() (string, error) {
installDir, err := getInstallDir()
installDir, err := InstallDir()
if err != nil {
return "", err
}
Expand All @@ -254,7 +254,7 @@ func getBinDir() (string, error) {
// getLibDir returns the absolute path of the directory where Java tool library files (such as .jar
// or .exe files) are stored.
func getLibDir() (string, error) {
installDir, err := getInstallDir()
installDir, err := InstallDir()
if err != nil {
return "", err
}
Expand Down
1 change: 1 addition & 0 deletions internal/librarian/librarian.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func Run(ctx context.Context, args ...string) error {
publishCommand(),
tagCommand(),
versionCommand(),
debugCommand(),
},
}
return cmd.Run(ctx, args)
Expand Down
Loading