A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff below:

add preliminary support for vendor directories · golang/go@183cc0c · GitHub

@@ -215,6 +215,12 @@ func reloadPackage(arg string, stk *importStack) *Package {

215 215

return loadPackage(arg, stk)

216 216

}

217 217 218 +

// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1.

219 +

// The variable is obnoxiously long so that years from now when people find it in

220 +

// their profiles and wonder what it does, there is some chance that a web search

221 +

// might answer the question.

222 +

var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"

223 + 218 224

// dirToImportPath returns the pseudo-import path we use for a package

219 225

// outside the Go path. It begins with _/ and then contains the full path

220 226

// to the directory. If the package lives in c:\home\gopher\my\pkg then

@@ -239,23 +245,33 @@ func makeImportValid(r rune) rune {

239 245

// but possibly a local import path (an absolute file system path or one beginning

240 246

// with ./ or ../). A local relative path is interpreted relative to srcDir.

241 247

// It returns a *Package describing the package found in that directory.

242 -

func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {

248 +

func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position) *Package {

243 249

stk.push(path)

244 250

defer stk.pop()

245 251 246 252

// Determine canonical identifier for this package.

247 253

// For a local import the identifier is the pseudo-import path

248 254

// we create from the full directory to the package.

249 255

// Otherwise it is the usual import path.

256 +

// For vendored imports, it is the expanded form.

250 257

importPath := path

258 +

origPath := path

251 259

isLocal := build.IsLocalImport(path)

260 +

var vendorSearch []string

252 261

if isLocal {

253 262

importPath = dirToImportPath(filepath.Join(srcDir, path))

263 +

} else {

264 +

path, vendorSearch = vendoredImportPath(parent, path)

265 +

importPath = path

254 266

}

267 + 255 268

if p := packageCache[importPath]; p != nil {

256 269

if perr := disallowInternal(srcDir, p, stk); perr != p {

257 270

return perr

258 271

}

272 +

if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {

273 +

return perr

274 +

}

259 275

return reusePackage(p, stk)

260 276

}

261 277

@@ -271,11 +287,33 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.

271 287

// TODO: After Go 1, decide when to pass build.AllowBinary here.

272 288

// See issue 3268 for mistakes to avoid.

273 289

bp, err := buildContext.Import(path, srcDir, build.ImportComment)

290 + 291 +

// If we got an error from go/build about package not found,

292 +

// it contains the directories from $GOROOT and $GOPATH that

293 +

// were searched. Add to that message the vendor directories

294 +

// that were searched.

295 +

if err != nil && len(vendorSearch) > 0 {

296 +

// NOTE(rsc): The direct text manipulation here is fairly awful,

297 +

// but it avoids defining new go/build API (an exported error type)

298 +

// late in the Go 1.5 release cycle. If this turns out to be a more general

299 +

// problem we could define a real error type when the decision can be

300 +

// considered more carefully.

301 +

text := err.Error()

302 +

if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") {

303 +

old := strings.SplitAfter(text, "\n")

304 +

lines := []string{old[0]}

305 +

for _, dir := range vendorSearch {

306 +

lines = append(lines, "\t"+dir+" (vendor tree)\n")

307 +

}

308 +

lines = append(lines, old[1:]...)

309 +

err = errors.New(strings.Join(lines, ""))

310 +

}

311 +

}

274 312

bp.ImportPath = importPath

275 313

if gobin != "" {

276 314

bp.BinDir = gobin

277 315

}

278 -

if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {

316 +

if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && (!go15VendorExperiment || !strings.Contains(path, "/vendor/")) {

279 317

err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)

280 318

}

281 319

p.load(stk, bp, err)

@@ -288,10 +326,81 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.

288 326

if perr := disallowInternal(srcDir, p, stk); perr != p {

289 327

return perr

290 328

}

329 +

if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {

330 +

return perr

331 +

}

291 332 292 333

return p

293 334

}

294 335 336 +

var isDirCache = map[string]bool{}

337 + 338 +

func isDir(path string) bool {

339 +

result, ok := isDirCache[path]

340 +

if ok {

341 +

return result

342 +

}

343 + 344 +

fi, err := os.Stat(path)

345 +

result = err == nil && fi.IsDir()

346 +

isDirCache[path] = result

347 +

return result

348 +

}

349 + 350 +

// vendoredImportPath returns the expansion of path when it appears in parent.

351 +

// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,

352 +

// x/vendor/path, vendor/path, or else stay x/y/z if none of those exist.

353 +

// vendoredImportPath returns the expanded path or, if no expansion is found, the original.

354 +

// If no epxansion is found, vendoredImportPath also returns a list of vendor directories

355 +

// it searched along the way, to help prepare a useful error message should path turn

356 +

// out not to exist.

357 +

func vendoredImportPath(parent *Package, path string) (found string, searched []string) {

358 +

if parent == nil || !go15VendorExperiment {

359 +

return path, nil

360 +

}

361 +

dir := filepath.Clean(parent.Dir)

362 +

root := filepath.Clean(parent.Root)

363 +

if !strings.HasPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {

364 +

fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))

365 +

}

366 +

vpath := "vendor/" + path

367 +

for i := len(dir); i >= len(root); i-- {

368 +

if i < len(dir) && dir[i] != filepath.Separator {

369 +

continue

370 +

}

371 +

// Note: checking for the vendor directory before checking

372 +

// for the vendor/path directory helps us hit the

373 +

// isDir cache more often. It also helps us prepare a more useful

374 +

// list of places we looked, to report when an import is not found.

375 +

if !isDir(filepath.Join(dir[:i], "vendor")) {

376 +

continue

377 +

}

378 +

targ := filepath.Join(dir[:i], vpath)

379 +

if isDir(targ) {

380 +

// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.

381 +

// We know the import path for parent's dir.

382 +

// We chopped off some number of path elements and

383 +

// added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.

384 +

// Now we want to know the import path for that directory.

385 +

// Construct it by chopping the same number of path elements

386 +

// (actually the same number of bytes) from parent's import path

387 +

// and then append /vendor/path.

388 +

chopped := len(dir) - i

389 +

if chopped == len(parent.ImportPath)+1 {

390 +

// We walked up from c:\gopath\src\foo\bar

391 +

// and found c:\gopath\src\vendor\path.

392 +

// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).

393 +

// Use "vendor/path" without any prefix.

394 +

return vpath, nil

395 +

}

396 +

return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil

397 +

}

398 +

// Note the existence of a vendor directory in case path is not found anywhere.

399 +

searched = append(searched, targ)

400 +

}

401 +

return path, searched

402 +

}

403 + 295 404

// reusePackage reuses package p to satisfy the import at the top

296 405

// of the import stack stk. If this use causes an import loop,

297 406

// reusePackage updates p's error information to record the loop.

@@ -384,6 +493,101 @@ func findInternal(path string) (index int, ok bool) {

384 493

return 0, false

385 494

}

386 495 496 +

// disallowVendor checks that srcDir is allowed to import p as path.

497 +

// If the import is allowed, disallowVendor returns the original package p.

498 +

// If not, it returns a new package containing just an appropriate error.

499 +

func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {

500 +

if !go15VendorExperiment {

501 +

return p

502 +

}

503 + 504 +

// The stack includes p.ImportPath.

505 +

// If that's the only thing on the stack, we started

506 +

// with a name given on the command line, not an

507 +

// import. Anything listed on the command line is fine.

508 +

if len(*stk) == 1 {

509 +

return p

510 +

}

511 + 512 +

if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {

513 +

return perr

514 +

}

515 + 516 +

// Paths like x/vendor/y must be imported as y, never as x/vendor/y.

517 +

if i, ok := findVendor(path); ok {

518 +

perr := *p

519 +

perr.Error = &PackageError{

520 +

ImportStack: stk.copy(),

521 +

Err: "must be imported as " + path[i+len("vendor/"):],

522 +

}

523 +

perr.Incomplete = true

524 +

return &perr

525 +

}

526 + 527 +

return p

528 +

}

529 + 530 +

// disallowVendorVisibility checks that srcDir is allowed to import p.

531 +

// The rules are the same as for /internal/ except that a path ending in /vendor

532 +

// is not subject to the rules, only subdirectories of vendor.

533 +

// This allows people to have packages and commands named vendor,

534 +

// for maximal compatibility with existing source trees.

535 +

func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package {

536 +

// The stack includes p.ImportPath.

537 +

// If that's the only thing on the stack, we started

538 +

// with a name given on the command line, not an

539 +

// import. Anything listed on the command line is fine.

540 +

if len(*stk) == 1 {

541 +

return p

542 +

}

543 + 544 +

// Check for "vendor" element.

545 +

i, ok := findVendor(p.ImportPath)

546 +

if !ok {

547 +

return p

548 +

}

549 + 550 +

// Vendor is present.

551 +

// Map import path back to directory corresponding to parent of vendor.

552 +

if i > 0 {

553 +

i-- // rewind over slash in ".../vendor"

554 +

}

555 +

parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]

556 +

if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {

557 +

return p

558 +

}

559 + 560 +

// Vendor is present, and srcDir is outside parent's tree. Not allowed.

561 +

perr := *p

562 +

perr.Error = &PackageError{

563 +

ImportStack: stk.copy(),

564 +

Err: "use of vendored package not allowed",

565 +

}

566 +

perr.Incomplete = true

567 +

return &perr

568 +

}

569 + 570 +

// findVendor looks for the last non-terminating "vendor" path element in the given import path.

571 +

// If there isn't one, findVendor returns ok=false.

572 +

// Otherwise, findInternal returns ok=true and the index of the "vendor".

573 +

//

574 +

// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,

575 +

// not the vendored copy of an import "" (the empty import path).

576 +

// This will allow people to have packages or commands named vendor.

577 +

// This may help reduce breakage, or it may just be confusing. We'll see.

578 +

func findVendor(path string) (index int, ok bool) {

579 +

// Two cases, depending on internal at start of string or not.

580 +

// The order matters: we must return the index of the final element,

581 +

// because the final one is where the effective import path starts.

582 +

switch {

583 +

case strings.Contains(path, "/vendor/"):

584 +

return strings.LastIndex(path, "/vendor/") + 1, true

585 +

case strings.HasPrefix(path, "vendor/"):

586 +

return 0, true

587 +

}

588 +

return 0, false

589 +

}

590 + 387 591

type targetDir int

388 592 389 593

const (

@@ -630,7 +834,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package

630 834

if path == "C" {

631 835

continue

632 836

}

633 -

p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])

837 +

p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path])

634 838

if p1.Name == "main" {

635 839

p.Error = &PackageError{

636 840

ImportStack: stk.copy(),

@@ -652,8 +856,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package

652 856

p.Error.Pos = pos[0].String()

653 857

}

654 858

}

655 -

path = p1.ImportPath

656 -

importPaths[i] = path

859 +

}

860 +

path = p1.ImportPath

861 +

importPaths[i] = path

862 +

if i < len(p.Imports) {

863 +

p.Imports[i] = path

657 864

}

658 865

deps[path] = p1

659 866

imports = append(imports, p1)

@@ -1294,7 +1501,7 @@ func loadPackage(arg string, stk *importStack) *Package {

1294 1501

}

1295 1502

}

1296 1503 1297 -

return loadImport(arg, cwd, stk, nil)

1504 +

return loadImport(arg, cwd, nil, stk, nil)

1298 1505

}

1299 1506 1300 1507

// packages returns the packages named by the


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4