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