github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/rule/platform_strings.go (about)

     1  /* Copyright 2017 The Bazel Authors. All rights reserved.
     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  
    16  package rule
    17  
    18  import (
    19  	"sort"
    20  	"strings"
    21  
    22  	bzl "github.com/bazelbuild/buildtools/build"
    23  )
    24  
    25  // PlatformConstraint represents a constraint_setting target for a particular
    26  // OS/arch combination.
    27  //
    28  // DEPRECATED: do not use outside language/go.
    29  type PlatformConstraint struct {
    30  	Platform
    31  	ConstraintPrefix string
    32  }
    33  
    34  func (p PlatformConstraint) String() string {
    35  	pStr := p.Platform.String()
    36  	if pStr == "" {
    37  		return ""
    38  	}
    39  	return p.ConstraintPrefix + pStr
    40  }
    41  
    42  // PlatformStrings contains a set of strings associated with a buildable
    43  // target in a package. This is used to store source file names,
    44  // import paths, and flags.
    45  //
    46  // Strings are stored in four sets: generic strings, OS-specific strings,
    47  // arch-specific strings, and OS-and-arch-specific strings. A string may not
    48  // be duplicated within a list or across sets; however, a string may appear
    49  // in more than one list within a set (e.g., in "linux" and "windows" within
    50  // the OS set). Strings within each list should be sorted, though this may
    51  // not be relied upon.
    52  //
    53  // DEPRECATED: do not use outside language/go. This type is Go-specific and
    54  // should be moved to the Go extension.
    55  type PlatformStrings struct {
    56  	// Generic is a list of strings not specific to any platform.
    57  	Generic []string
    58  
    59  	// OS is a map from an OS constraint to OS-specific strings.
    60  	OS map[string][]string
    61  
    62  	// Arch is a map from an architecture constraint to
    63  	// architecture-specific strings.
    64  	Arch map[string][]string
    65  
    66  	// Platform is a map from platform constraints to OS and
    67  	// architecture-specific strings.
    68  	Platform map[PlatformConstraint][]string
    69  }
    70  
    71  // HasExt returns whether this set contains a file with the given extension.
    72  func (ps *PlatformStrings) HasExt(ext string) bool {
    73  	return ps.firstExtFile(ext) != ""
    74  }
    75  
    76  func (ps *PlatformStrings) IsEmpty() bool {
    77  	return len(ps.Generic) == 0 && len(ps.OS) == 0 && len(ps.Arch) == 0 && len(ps.Platform) == 0
    78  }
    79  
    80  // Flat returns all the strings in the set, sorted and de-duplicated.
    81  func (ps *PlatformStrings) Flat() []string {
    82  	unique := make(map[string]struct{})
    83  	for _, s := range ps.Generic {
    84  		unique[s] = struct{}{}
    85  	}
    86  	for _, ss := range ps.OS {
    87  		for _, s := range ss {
    88  			unique[s] = struct{}{}
    89  		}
    90  	}
    91  	for _, ss := range ps.Arch {
    92  		for _, s := range ss {
    93  			unique[s] = struct{}{}
    94  		}
    95  	}
    96  	for _, ss := range ps.Platform {
    97  		for _, s := range ss {
    98  			unique[s] = struct{}{}
    99  		}
   100  	}
   101  	flat := make([]string, 0, len(unique))
   102  	for s := range unique {
   103  		flat = append(flat, s)
   104  	}
   105  	sort.Strings(flat)
   106  	return flat
   107  }
   108  
   109  func (ps *PlatformStrings) firstExtFile(ext string) string {
   110  	for _, f := range ps.Generic {
   111  		if strings.HasSuffix(f, ext) {
   112  			return f
   113  		}
   114  	}
   115  	for _, fs := range ps.OS {
   116  		for _, f := range fs {
   117  			if strings.HasSuffix(f, ext) {
   118  				return f
   119  			}
   120  		}
   121  	}
   122  	for _, fs := range ps.Arch {
   123  		for _, f := range fs {
   124  			if strings.HasSuffix(f, ext) {
   125  				return f
   126  			}
   127  		}
   128  	}
   129  	for _, fs := range ps.Platform {
   130  		for _, f := range fs {
   131  			if strings.HasSuffix(f, ext) {
   132  				return f
   133  			}
   134  		}
   135  	}
   136  	return ""
   137  }
   138  
   139  // Map applies a function that processes individual strings to the strings
   140  // in "ps" and returns a new PlatformStrings with the result. Empty strings
   141  // returned by the function are dropped.
   142  func (ps *PlatformStrings) Map(f func(s string) (string, error)) (PlatformStrings, []error) {
   143  	var errors []error
   144  	mapSlice := func(ss []string) ([]string, error) {
   145  		rs := make([]string, 0, len(ss))
   146  		for _, s := range ss {
   147  			if r, err := f(s); err != nil {
   148  				errors = append(errors, err)
   149  			} else if r != "" {
   150  				rs = append(rs, r)
   151  			}
   152  		}
   153  		return rs, nil
   154  	}
   155  	result, _ := ps.MapSlice(mapSlice)
   156  	return result, errors
   157  }
   158  
   159  // MapSlice applies a function that processes slices of strings to the strings
   160  // in "ps" and returns a new PlatformStrings with the results.
   161  func (ps *PlatformStrings) MapSlice(f func([]string) ([]string, error)) (PlatformStrings, []error) {
   162  	var errors []error
   163  
   164  	mapSlice := func(ss []string) []string {
   165  		rs, err := f(ss)
   166  		if err != nil {
   167  			errors = append(errors, err)
   168  			return nil
   169  		}
   170  		return rs
   171  	}
   172  
   173  	mapStringMap := func(m map[string][]string) map[string][]string {
   174  		if m == nil {
   175  			return nil
   176  		}
   177  		rm := make(map[string][]string)
   178  		for k, ss := range m {
   179  			ss = mapSlice(ss)
   180  			if len(ss) > 0 {
   181  				rm[k] = ss
   182  			}
   183  		}
   184  		if len(rm) == 0 {
   185  			return nil
   186  		}
   187  		return rm
   188  	}
   189  
   190  	mapPlatformMap := func(m map[PlatformConstraint][]string) map[PlatformConstraint][]string {
   191  		if m == nil {
   192  			return nil
   193  		}
   194  		rm := make(map[PlatformConstraint][]string)
   195  		for k, ss := range m {
   196  			ss = mapSlice(ss)
   197  			if len(ss) > 0 {
   198  				rm[k] = ss
   199  			}
   200  		}
   201  		if len(rm) == 0 {
   202  			return nil
   203  		}
   204  		return rm
   205  	}
   206  
   207  	result := PlatformStrings{
   208  		Generic:  mapSlice(ps.Generic),
   209  		OS:       mapStringMap(ps.OS),
   210  		Arch:     mapStringMap(ps.Arch),
   211  		Platform: mapPlatformMap(ps.Platform),
   212  	}
   213  	return result, errors
   214  }
   215  
   216  func (ps PlatformStrings) BzlExpr() bzl.Expr {
   217  	var pieces []bzl.Expr
   218  	if len(ps.Generic) > 0 {
   219  		pieces = append(pieces, ExprFromValue(ps.Generic))
   220  	}
   221  	if len(ps.OS) > 0 {
   222  		pieces = append(pieces, platformStringsOSArchDictExpr(ps.OS))
   223  	}
   224  	if len(ps.Arch) > 0 {
   225  		pieces = append(pieces, platformStringsOSArchDictExpr(ps.Arch))
   226  	}
   227  	if len(ps.Platform) > 0 {
   228  		pieces = append(pieces, platformStringsPlatformDictExpr(ps.Platform))
   229  	}
   230  	if len(pieces) == 0 {
   231  		return &bzl.ListExpr{}
   232  	} else if len(pieces) == 1 {
   233  		return pieces[0]
   234  	} else {
   235  		e := pieces[0]
   236  		if list, ok := e.(*bzl.ListExpr); ok {
   237  			list.ForceMultiLine = true
   238  		}
   239  		for _, piece := range pieces[1:] {
   240  			e = &bzl.BinaryExpr{X: e, Y: piece, Op: "+"}
   241  		}
   242  		return e
   243  	}
   244  }
   245  
   246  func platformStringsOSArchDictExpr(m map[string][]string) bzl.Expr {
   247  	s := make(SelectStringListValue)
   248  	for key, value := range m {
   249  		s[key] = value
   250  	}
   251  	s["//conditions:default"] = nil
   252  	return s.BzlExpr()
   253  }
   254  
   255  func platformStringsPlatformDictExpr(m map[PlatformConstraint][]string) bzl.Expr {
   256  	s := make(SelectStringListValue)
   257  	for key, value := range m {
   258  		s[key.String()] = value
   259  	}
   260  	s["//conditions:default"] = nil
   261  	return s.BzlExpr()
   262  }