fetchFile retrieves a single path's metadata and inline content via the REST Contents API. It returns a typed error when the path is a directory, symlink, or submodule. Content is populated only when the API returns it inline; larger files come back with empty content, and it is up to the caller to
(httpClient *http.Client, repo ghrepo.Interface, filePath, ref string)
| 126 | // it is up to the caller to fetch the raw bytes via fetchRawFile when the content is actually |
| 127 | // needed. |
| 128 | func fetchFile(httpClient *http.Client, repo ghrepo.Interface, filePath, ref string) (*repoFile, error) { |
| 129 | content, err := fetchContent(httpClient, repo, filePath, ref) |
| 130 | if err != nil { |
| 131 | return nil, err |
| 132 | } |
| 133 | |
| 134 | if content.Type != "file" { |
| 135 | // The path resolved to something other than a regular file. Use content.Path |
| 136 | // (the API-sanitized path) rather than the user input in these messages, so a |
| 137 | // crafted path cannot smuggle terminal escape sequences into our output. |
| 138 | switch content.Type { |
| 139 | case "dir": |
| 140 | return nil, fmt.Errorf("path %q is a directory; use `gh repo read-dir` instead", content.Path) |
| 141 | case "symlink": |
| 142 | return nil, fmt.Errorf("path %q is a symlink to %q which does not exist", content.Path, content.Target) |
| 143 | case "submodule": |
| 144 | return nil, fmt.Errorf("path %q is a submodule (%s at %s)", content.Path, content.SubmoduleGitURL, content.SHA) |
| 145 | default: |
| 146 | return nil, fmt.Errorf("path %q is not a regular file (type: %s)", content.Path, content.Type) |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | file := &repoFile{ |
| 151 | Name: content.Name, |
| 152 | Path: content.Path, |
| 153 | SHA: content.SHA, |
| 154 | Size: content.Size, |
| 155 | URL: content.URL, |
| 156 | HTMLURL: content.HTMLURL, |
| 157 | GitURL: content.GitURL, |
| 158 | DownloadURL: content.DownloadURL, |
| 159 | Type: content.Type, |
| 160 | Encoding: content.Encoding, |
| 161 | } |
| 162 | |
| 163 | if content.Encoding == "base64" && content.Content != "" { |
| 164 | decoded, err := base64.StdEncoding.DecodeString(content.Content) |
| 165 | if err != nil { |
| 166 | return nil, fmt.Errorf("failed to decode base64 file content: %w", err) |
| 167 | } |
| 168 | file.Content = decoded |
| 169 | } |
| 170 | |
| 171 | return file, nil |
| 172 | } |
| 173 | |
| 174 | // fetchRawFile retrieves the raw bytes of a file, used for files larger than the |
| 175 | // 1 MB inline content limit of the Contents API. |
no test coverage detected