Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lockfiles): add rust implementation for yarn1 #5255

Merged
merged 11 commits into from
Jun 13, 2023
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
255 changes: 126 additions & 129 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions cli/internal/ffi/ffi.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ func toPackageManager(packageManager string) ffi_proto.PackageManager {
return ffi_proto.PackageManager_BERRY
case "pnpm":
return ffi_proto.PackageManager_PNPM
case "yarn":
return ffi_proto.PackageManager_YARN
default:
panic(fmt.Sprintf("Invalid package manager string: %s", packageManager))
}
Expand Down
11 changes: 7 additions & 4 deletions cli/internal/ffi/proto/messages.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions cli/internal/lockfile/lockfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ func AllTransitiveClosures(
if lf, ok := lockFile.(*PnpmLockfile); ok {
return rustTransitiveDeps(lf.contents, "pnpm", workspaces, nil)
}
if lf, ok := lockFile.(*YarnLockfile); ok {
return rustTransitiveDeps(lf.contents, "yarn", workspaces, nil)
}

g := new(errgroup.Group)
c := make(chan closureMsg, len(workspaces))
Expand Down
99 changes: 20 additions & 79 deletions cli/internal/lockfile/yarn_lockfile.go
Original file line number Diff line number Diff line change
@@ -1,82 +1,50 @@
package lockfile

import (
"bytes"
"fmt"
"io"

"github.com/andybalholm/crlf"
"github.com/iseki0/go-yarnlock"
"github.com/pkg/errors"
"github.com/vercel/turbo/cli/internal/ffi"
"github.com/vercel/turbo/cli/internal/turbopath"
)

var _crlfLiteral = []byte("\r\n")

// YarnLockfile representation of yarn lockfile
type YarnLockfile struct {
inner yarnlock.LockFile
hasCRLF bool
contents []byte
}

var _ Lockfile = (*YarnLockfile)(nil)

// ResolvePackage Given a package and version returns the key, resolved version, and if it was found
func (l *YarnLockfile) ResolvePackage(_workspacePath turbopath.AnchoredUnixPath, name string, version string) (Package, error) {
for _, key := range yarnPossibleKeys(name, version) {
if entry, ok := (l.inner)[key]; ok {
return Package{
Found: true,
Key: key,
Version: entry.Version,
}, nil
}
}

return Package{}, nil
// This is only used when doing calculating the transitive deps, but Rust
// implementations do this calculation on the Rust side.
panic("Unreachable")
}

// AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package
func (l *YarnLockfile) AllDependencies(key string) (map[string]string, bool) {
deps := map[string]string{}
entry, ok := (l.inner)[key]
if !ok {
return deps, false
}

for name, version := range entry.Dependencies {
deps[name] = version
}
for name, version := range entry.OptionalDependencies {
deps[name] = version
}

return deps, true
// This is only used when doing calculating the transitive deps, but Rust
// implementations do this calculation on the Rust side.
panic("Unreachable")
}

// Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given
func (l *YarnLockfile) Subgraph(_ []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
lockfile := make(map[string]yarnlock.LockFileEntry, len(packages))
for _, key := range packages {
entry, ok := (l.inner)[key]
if ok {
lockfile[key] = entry
}
func (l *YarnLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) {
workspaces := make([]string, len(workspacePackages))
for i, workspace := range workspacePackages {
workspaces[i] = workspace.ToUnixPath().ToString()
}

return &YarnLockfile{lockfile, l.hasCRLF}, nil
contents, err := ffi.Subgraph("yarn", l.contents, workspaces, packages, nil)
if err != nil {
return nil, err
}
return &YarnLockfile{contents: contents}, nil
}

// Encode encode the lockfile representation and write it to the given writer
func (l *YarnLockfile) Encode(w io.Writer) error {
writer := w
if l.hasCRLF {
writer = crlf.NewWriter(w)
}
if err := l.inner.Encode(writer); err != nil {
return errors.Wrap(err, "Unable to encode yarn.lock")
}
return nil
_, err := w.Write(l.contents)
return err
}

// Patches return a list of patches used in the lockfile
Expand All @@ -86,24 +54,7 @@ func (l *YarnLockfile) Patches() []turbopath.AnchoredUnixPath {

// DecodeYarnLockfile Takes the contents of a yarn lockfile and returns a struct representation
func DecodeYarnLockfile(contents []byte) (*YarnLockfile, error) {
lockfile, err := yarnlock.ParseLockFileData(contents)
hasCRLF := bytes.HasSuffix(contents, _crlfLiteral)
newline := []byte("\n")

// there's no trailing newline for this file, need to inspect more to see newline style
if !hasCRLF && !bytes.HasSuffix(contents, newline) {
firstNewline := bytes.IndexByte(contents, newline[0])
if firstNewline != -1 && firstNewline != 0 {
byteBeforeNewline := contents[firstNewline-1]
hasCRLF = byteBeforeNewline == '\r'
}
}

if err != nil {
return nil, errors.Wrap(err, "Unable to decode yarn.lock")
}

return &YarnLockfile{lockfile, hasCRLF}, nil
return &YarnLockfile{contents: contents}, nil
}

// GlobalChange checks if there are any differences between lockfiles that would completely invalidate
Expand All @@ -112,13 +63,3 @@ func (l *YarnLockfile) GlobalChange(other Lockfile) bool {
_, ok := other.(*YarnLockfile)
return !ok
}

func yarnPossibleKeys(name string, version string) []string {
return []string{
fmt.Sprintf("%v@%v", name, version),
fmt.Sprintf("%v@npm:%v", name, version),
fmt.Sprintf("%v@file:%v", name, version),
fmt.Sprintf("%v@workspace:%v", name, version),
fmt.Sprintf("%v@yarn:%v", name, version),
}
}
51 changes: 0 additions & 51 deletions cli/internal/lockfile/yarn_lockfile_test.go

This file was deleted.

1 change: 1 addition & 0 deletions crates/turborepo-ffi/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ enum PackageManager {
NPM = 0;
BERRY = 1;
PNPM = 2;
YARN = 3;
}

message PackageDependency {
Expand Down
25 changes: 24 additions & 1 deletion crates/turborepo-ffi/src/lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use std::{
};

use thiserror::Error;
use turborepo_lockfiles::{self, BerryLockfile, LockfileData, NpmLockfile, Package, PnpmLockfile};
use turborepo_lockfiles::{
self, BerryLockfile, LockfileData, NpmLockfile, Package, PnpmLockfile, Yarn1Lockfile,
};

use super::{proto, Buffer};

Expand Down Expand Up @@ -51,6 +53,7 @@ fn transitive_closure_inner(buf: Buffer) -> Result<proto::WorkspaceDependencies,
proto::PackageManager::Npm => npm_transitive_closure_inner(request),
proto::PackageManager::Berry => berry_transitive_closure_inner(request),
proto::PackageManager::Pnpm => pnpm_transitive_closure_inner(request),
proto::PackageManager::Yarn => yarn_transitive_closure_inner(request),
}
}

Expand Down Expand Up @@ -106,6 +109,23 @@ fn pnpm_transitive_closure_inner(
Ok(dependencies.into())
}

fn yarn_transitive_closure_inner(
request: proto::TransitiveDepsRequest,
) -> Result<proto::WorkspaceDependencies, Error> {
let proto::TransitiveDepsRequest {
contents,
workspaces,
..
} = request;
let lockfile =
Yarn1Lockfile::from_bytes(contents.as_slice()).map_err(turborepo_lockfiles::Error::from)?;
let dependencies = turborepo_lockfiles::all_transitive_closures(
&lockfile,
workspaces.into_iter().map(|(k, v)| (k, v.into())).collect(),
)?;
Ok(dependencies.into())
}

#[no_mangle]
pub extern "C" fn subgraph(buf: Buffer) -> Buffer {
use proto::subgraph_response::Response;
Expand Down Expand Up @@ -141,6 +161,7 @@ fn subgraph_inner(buf: Buffer) -> Result<Vec<u8>, Error> {
proto::PackageManager::Pnpm => {
turborepo_lockfiles::pnpm_subgraph(&contents, &workspaces, &packages)?
}
proto::PackageManager::Yarn => turborepo_lockfiles::yarn_subgraph(&contents, &packages)?,
};
Ok(contents)
}
Expand Down Expand Up @@ -205,6 +226,7 @@ fn global_change_inner(buf: Buffer) -> Result<bool, Error> {
&request.prev_contents,
&request.curr_contents,
)?),
proto::PackageManager::Yarn => Ok(false),
}
}

Expand Down Expand Up @@ -248,6 +270,7 @@ impl fmt::Display for proto::PackageManager {
proto::PackageManager::Npm => "npm",
proto::PackageManager::Berry => "berry",
proto::PackageManager::Pnpm => "pnpm",
proto::PackageManager::Yarn => "yarn",
})
}
}
50 changes: 50 additions & 0 deletions crates/turborepo-lockfiles/fixtures/yarn1.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


nextjs@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/nextjs/-/nextjs-0.0.3.tgz#4f4d1d6a257be920d9b9649d4d9522c724a4e543"
integrity sha512-mYbDUo4/sRAZ8TqK63PCpYnFiLg7BICG/ot9+guOrUKd4/Fo71ZmEQ41IZbH6nqbQvG7SXTBuofJXAIWfNho0w==

turbo-darwin-64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.9.3.tgz#29470b902a1418dae8a88b2620caf917b27480bc"
integrity sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==

turbo-darwin-arm64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.9.3.tgz#0eb404d6101ba69eab8522b16260a4eb50885e6c"
integrity sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==

turbo-linux-64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.9.3.tgz#dbce8fd50edee1319f17800ee38e7c4749ab0cb0"
integrity sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==

turbo-linux-arm64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.9.3.tgz#636b77fde17c7a5cdef8a20616ff57f08c785345"
integrity sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==

turbo-windows-64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.9.3.tgz#c65625c222456161b0b4d000ec7f50e372332825"
integrity sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==

turbo-windows-arm64@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.9.3.tgz#86e105692ad6ba935eff0284522bdf7728a2e517"
integrity sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==

turbo@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.9.3.tgz#911012624f647f98d9788a08e25b98e38cdd48b2"
integrity sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==
optionalDependencies:
turbo-darwin-64 "1.9.3"
turbo-darwin-arm64 "1.9.3"
turbo-linux-64 "1.9.3"
turbo-linux-arm64 "1.9.3"
turbo-windows-64 "1.9.3"
turbo-windows-arm64 "1.9.3"
2 changes: 2 additions & 0 deletions crates/turborepo-lockfiles/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ pub enum Error {
UnsupportedNpmVersion,
#[error(transparent)]
Pnpm(#[from] crate::pnpm::Error),
#[error(transparent)]
Yarn1(#[from] crate::yarn1::Error),
}
2 changes: 2 additions & 0 deletions crates/turborepo-lockfiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod berry;
mod error;
mod npm;
mod pnpm;
mod yarn1;

use std::collections::{HashMap, HashSet};

Expand All @@ -12,6 +13,7 @@ pub use error::Error;
pub use npm::*;
pub use pnpm::{pnpm_global_change, pnpm_subgraph, PnpmLockfile};
use serde::Serialize;
pub use yarn1::{yarn_subgraph, Yarn1Lockfile};

#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Serialize)]
pub struct Package {
Expand Down
Loading