Skip to content

Conversation

@MeteorsLiu
Copy link
Collaborator

@MeteorsLiu MeteorsLiu commented Dec 19, 2025

This PR is NOT considered to be merged, which is a demo to show how LLAR works and will be separated into multiple small PRs, please do not review.

@MeteorsLiu MeteorsLiu changed the title MVP [WIP]MVP Dec 19, 2025
@gemini-code-assist
Copy link

Summary of Changes

Hello @MeteorsLiu, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request establishes the foundational components for llar, a new cloud-based package manager. It delivers a suite of command-line tools that enable users to initialize new modules, add and manage dependencies, resolve version conflicts using the Minimal Version Selection algorithm, and build or install packages. The system is designed for flexibility, using Go+ "formula" files to encapsulate module-specific build instructions and integrating seamlessly with Git for source code management. This MVP provides a robust framework for efficient and reliable package handling.

Highlights

  • New Package Manager CLI: Introduction of llar with core commands like init, get, tidy, build, and install for module management.
  • Go+ (Gop) Formula-based Builds: Utilizes .gox files as "formulas" to define module build logic and dependencies, interpreted by ixgo.
  • Minimal Version Selection (MVS): Implements a robust dependency resolution algorithm to determine compatible module versions.
  • Comprehensive Build System: Includes features for fetching source code via Git, caching build artifacts, managing build environments, and integrating with pkg-config.
  • Cross-Platform File Locking: Ensures safe concurrent operations across different operating systems during build processes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant amount of new functionality, laying the groundwork for the llar command-line tool with build, get, init, install, and tidy commands. The changes include core logic for module loading, version selection using MVS, and interaction with version control systems.

While the PR is marked as a work-in-progress and not ready for review, I've taken a look at the code and have a few high-level observations and specific suggestions that might be helpful as you continue development.

There are several places where errors are handled by panicking, which could be refactored to return errors for more idiomatic Go error handling. I've also noticed some non-deterministic behavior in version selection and opportunities to reduce code duplication.

One important point to consider is the inclusion of pkgs/gnu/sort.go, which appears to be licensed under LGPLv3+. Please ensure that this is compatible with the project's overall license.

My detailed comments are on the specific files.

Comment on lines 53 to 57
var currentVersion string
for ver := range v.Dependencies {
currentVersion = ver
break
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The way currentVersion is selected is non-deterministic. Iterating over a map in Go does not guarantee any specific order. If versions.json contains multiple version keys in Dependencies, this could lead to different versions being built on different runs. You should define a deterministic way to select the version, for example, by sorting the keys and picking the highest version according to some versioning scheme.

Comment on lines 38 to 42
var currentVersion string
for ver := range v.Dependencies {
currentVersion = ver
break
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to build.go, the selection of currentVersion here is non-deterministic due to iterating over a map without a guaranteed order. This can lead to inconsistent behavior. Please select the version in a deterministic way.

Comment on lines 53 to 62
func execCommand(dir, mainCmd string, subcmd ...string) []byte {
cmd := exec.Command(mainCmd, subcmd...)
cmd.Dir = dir
cmd.Stderr = os.Stderr
ret, err := cmd.Output()
if err != nil {
panic(string(ret))
}
return ret
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The execCommand function panics on error. This is generally not idiomatic Go for error handling, as it forces callers to use defer and recover. It's better to return the error and let the caller decide how to handle it. Panicking can make control flow harder to understand and debug.

}
compare, err := formulaContext.comparatorOf(p)
if err != nil {
panic(err)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This function panics if formulaContext.comparatorOf returns an error. This can crash the program. It's better to handle the error gracefully, for example by propagating it up the call stack. Panics should be reserved for unrecoverable errors, but an error loading a comparator seems like something that could be handled. Since the cmp function signature doesn't allow returning an error, you might need to preload comparators before starting the MVS process.

ctx := context.Background()

builder := build.NewBuilder()
if err := builder.Init(ctx, vcs.NewGitVCS(), "https://github.com/aspect-build/llb-formulas"); err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The formula repository URL is hardcoded. It would be more flexible to make this configurable, for example, through a command-line flag or an environment variable. This would allow users to use their own private formula repositories.

ctx := context.Background()

builder := build.NewBuilder()
if err := builder.Init(ctx, vcs.NewGitVCS(), "https://github.com/MeteorsLiu/llarmvp-formula"); err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The formula repository URL is hardcoded. It would be more flexible to make this configurable, for example, through a command-line flag or an environment variable. This would allow users to use their own private formula repositories.

Comment on lines 71 to 94
// Handle verbose output
var savedStdout, savedStderr *os.File
if !installVerbose {
// Redirect stdout/stderr for formulas
for i := range formulas {
formulas[i].SetStdout(io.Discard)
formulas[i].SetStderr(io.Discard)
}

// Also redirect os.Stdout/os.Stderr
savedStdout = os.Stdout
savedStderr = os.Stderr
devNull, err := os.Open(os.DevNull)
if err != nil {
return fmt.Errorf("failed to open devnull: %w", err)
}
os.Stdout = devNull
os.Stderr = devNull
defer func() {
devNull.Close()
os.Stdout = savedStdout
os.Stderr = savedStderr
}()
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for redirecting stdout/stderr is duplicated in cmd/llar/internal/build.go. To improve maintainability, consider refactoring this logic into a shared helper function. This function could take a boolean verbose flag and a function to execute while output is suppressed, and it would handle the redirection and restoration of os.Stdout and os.Stderr.

}

// parseModuleArg parses a module argument in the form "owner/repo@version" or "owner/repo".
func parseModuleArg(arg string) (modID, version string) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function parseModuleArg is also used by the get command. It would be better to move this and other shared utility functions (like printPkgConfigInfo) into a separate util.go file within the internal package to improve code organization and avoid potential circular dependencies.

Comment on lines 164 to 168
if out, err := cmd.Output(); err == nil {
if result := strings.TrimSpace(string(out)); result != "" {
fmt.Printf("%s: %s\n", pkgName, result)
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Errors from pkg-config are silently ignored here. If pkg-config fails (e.g., the package is not found, or pkg-config itself is not installed), the error will be suppressed. This can lead to silent build failures or unexpected behavior. You should at least log the error, especially in verbose mode.

		if out, err := cmd.Output(); err != nil {
			if installVerbose {
				fmt.Fprintf(os.Stderr, "pkg-config for %s failed: %v\n", pkgName, err)
			}
		} else {
			if result := strings.TrimSpace(string(out)); result != "" {
				fmt.Printf("%s: %s\n", pkgName, result)
			}
		}

return depInTable.ModuleID == dep.ModuleID
})
if idx < 0 {
// It seems safe to drop deps here, because we resolve deps recursively and finally we will find that dep.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment here says 'It seems safe to drop deps here'. Silently dropping a dependency because its version couldn't be resolved could lead to subtle and hard-to-debug issues later in the build process. It would be safer to return an error if a dependency version cannot be resolved, or at least log a warning.

- Move Use method from ModuleF to Project
- Simplify Builder by removing newRepo injection
- Fix source directory and build output paths
- Update tests and fixtures accordingly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant