Repository: syncthing/syncthing
File: lib/ignore/ignore.go (Go)

Code before:
	if err != nil {
		fd.Close()
	}

	return fd, info, err
}

func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetector, linesSeen map[string]struct{}) ([]Pattern, error) {
	// Allow escaping the folders filesystem.
	// TODO: Deprecate, somehow?
	if filesystem.Type() == fs.FilesystemTypeBasic {
		uri := filesystem.URI()
		joined := filepath.Join(uri, file)
		if !fs.IsParent(joined, uri) {
			filesystem = fs.NewFilesystem(filesystem.Type(), filepath.Dir(joined))
			file = filepath.Base(joined)
		}
	}

	if cd.Seen(filesystem, file) {
		return nil, parseError(fmt.Errorf("multiple include of ignore file %q", file))
	}

	fd, info, err := loadIgnoreFile(filesystem, file)
	if err != nil {
		return nil, parseError(fmt.Errorf("could not load included ignore file: %v", err))
	}
	defer fd.Close()

	cd.Remember(filesystem, file, info.ModTime())

	_, patterns, err := parseIgnoreFile(filesystem, fd, file, cd, linesSeen)
	return patterns, err
}

func parseLine(line string) ([]Pattern, error) {
	pattern := Pattern{
		result: defaultResult,
	}

	// Allow prefixes to be specified in any order, but only once.
	var seenPrefix [3]bool

	for {
		if strings.HasPrefix(line, "!") && !seenPrefix[0] {
			seenPrefix[0] = true
			line = line[1:]
			pattern.result ^= resultInclude
		} else if strings.HasPrefix(line, "(?i)") && !seenPrefix[1] {
			seenPrefix[1] = true
			pattern.result |= resultFoldCase

Review comment (bug):
Should use to use `%w` to preserve erro chain. And the inner error already signifies that something went wrong, the wrapping context could be more terse to shrink the overall length:

```suggestion
		return nil, parseError(fmt.Errorf("included ignore file: %w", err))
```


Code after:
	if err != nil {
		fd.Close()
	}

	return fd, info, err
}

func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetector, linesSeen map[string]struct{}) ([]Pattern, error) {
	// Allow escaping the folders filesystem.
	// TODO: Deprecate, somehow?
	if filesystem.Type() == fs.FilesystemTypeBasic {
		uri := filesystem.URI()
		joined := filepath.Join(uri, file)
		if !fs.IsParent(joined, uri) {
			filesystem = fs.NewFilesystem(filesystem.Type(), filepath.Dir(joined))
			file = filepath.Base(joined)
		}
	}

	if cd.Seen(filesystem, file) {
		return nil, errors.New("multiple include")
	}

	fd, info, err := loadIgnoreFile(filesystem, file)
	if err != nil {
		// isNotExist is considered "ok" in a sense of that a folder doesn't have to act
		// upon it. This is because it is allowed for .stignore to not exist. However,
		// included ignore files are not allowed to be missing and these errors should be
		// acted upon on. So we don't perserve the error chain here and manually set an
		// error instead, if the file is missing.
		if fs.IsNotExist(err) {
			err = errors.New("file not found")
		}
		return nil, err
	}
	defer fd.Close()

	cd.Remember(filesystem, file, info.ModTime())

	_, patterns, err := parseIgnoreFile(filesystem, fd, file, cd, linesSeen)
	return patterns, err
}

func parseLine(line string) ([]Pattern, error) {
	pattern := Pattern{
		result: defaultResult,
	}

	// Allow prefixes to be specified in any order, but only once.
	var seenPrefix [3]bool