github.com/google/osv-scalibr@v0.4.1/guidedremediation/internal/parser/parser.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package parser provides functions for parsing and writing manifest and lockfile files.
    16  package parser
    17  
    18  import (
    19  	"fmt"
    20  	"path/filepath"
    21  
    22  	"deps.dev/util/resolve"
    23  	scalibrfs "github.com/google/osv-scalibr/fs"
    24  	"github.com/google/osv-scalibr/guidedremediation/internal/lockfile"
    25  	"github.com/google/osv-scalibr/guidedremediation/internal/manifest"
    26  	"github.com/google/osv-scalibr/guidedremediation/result"
    27  )
    28  
    29  // ParseManifest parses a manifest file into a manifest.Manifest.
    30  func ParseManifest(path string, rw manifest.ReadWriter) (manifest.Manifest, error) {
    31  	fsys, path, err := fsAndPath(path)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	m, err := rw.Read(path, fsys)
    37  	if err != nil {
    38  		return nil, fmt.Errorf("error reading manifest: %w", err)
    39  	}
    40  	return m, nil
    41  }
    42  
    43  // ParseLockfile parses a lockfile file into a resolve.Graph.
    44  func ParseLockfile(path string, rw lockfile.ReadWriter) (*resolve.Graph, error) {
    45  	fsys, path, err := fsAndPath(path)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	g, err := rw.Read(path, fsys)
    51  	if err != nil {
    52  		return nil, fmt.Errorf("error reading lockfile: %w", err)
    53  	}
    54  	return g, nil
    55  }
    56  
    57  // WriteManifestPatches writes the patches to the manifest file.
    58  func WriteManifestPatches(path string, m manifest.Manifest, patches []result.Patch, rw manifest.ReadWriter) error {
    59  	fsys, _, err := fsAndPath(path)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	return rw.Write(m, fsys, patches, path)
    65  }
    66  
    67  // WriteLockfilePatches writes the patches to the lockfile file.
    68  func WriteLockfilePatches(path string, patches []result.Patch, rw lockfile.ReadWriter) error {
    69  	fsys, relPath, err := fsAndPath(path)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	return rw.Write(relPath, fsys, patches, path)
    75  }
    76  
    77  func fsAndPath(path string) (scalibrfs.FS, string, error) {
    78  	// We need a DirFS that can potentially access files in parent directories from the file.
    79  	// But you cannot escape the base directory of dirfs.
    80  	// e.g. "pkg/core/pom.xml" may have a parent at "pkg/parent/pom.xml",
    81  	// if we had fsys := scalibrfs.DirFS("pkg/core"), we can't do fsys.Open("../parent/pom.xml")
    82  	//
    83  	// Since we don't know ahead of time which files might be needed,
    84  	// we must use the system root as the directory.
    85  
    86  	absPath, err := filepath.Abs(path)
    87  	if err != nil {
    88  		return nil, "", err
    89  	}
    90  
    91  	// Get the path relative to the root (i.e. without the leading '/')
    92  	// On Windows, we need the path relative to the drive letter,
    93  	// which also means we can't open files across drives.
    94  	root := filepath.VolumeName(absPath) + "/"
    95  	relPath, err := filepath.Rel(root, absPath)
    96  	if err != nil {
    97  		return nil, "", err
    98  	}
    99  	relPath = filepath.ToSlash(relPath)
   100  
   101  	return scalibrfs.DirFS(root), relPath, nil
   102  }