GetDiffPreview produces and returns diff result of a file which is not yet committed.
(branch, treePath, content string)
| 244 | |
| 245 | // GetDiffPreview produces and returns diff result of a file which is not yet committed. |
| 246 | func (r *Repository) GetDiffPreview(branch, treePath, content string) (*gitutil.Diff, error) { |
| 247 | // 🚨 SECURITY: Prevent uploading files into the ".git" directory. |
| 248 | if isRepositoryGitPath(treePath) { |
| 249 | return nil, errors.Errorf("bad tree path %q", treePath) |
| 250 | } |
| 251 | |
| 252 | repoWorkingPool.CheckIn(com.ToStr(r.ID)) |
| 253 | defer repoWorkingPool.CheckOut(com.ToStr(r.ID)) |
| 254 | |
| 255 | if err := r.DiscardLocalRepoBranchChanges(branch); err != nil { |
| 256 | return nil, errors.Newf("discard local repo branch[%s] changes: %v", branch, err) |
| 257 | } else if err = r.UpdateLocalCopyBranch(branch); err != nil { |
| 258 | return nil, errors.Newf("update local copy branch[%s]: %v", branch, err) |
| 259 | } |
| 260 | |
| 261 | localPath := r.LocalCopyPath() |
| 262 | filePath := path.Join(localPath, treePath) |
| 263 | |
| 264 | // 🚨 SECURITY: Prevent touching files in surprising places, reject operations |
| 265 | // that involve symlinks. |
| 266 | if hasSymlinkInPath(localPath, treePath) { |
| 267 | return nil, errors.New("cannot update file with symbolic link in path") |
| 268 | } |
| 269 | |
| 270 | if err := os.MkdirAll(path.Dir(filePath), os.ModePerm); err != nil { |
| 271 | return nil, errors.Wrap(err, "create parent directories") |
| 272 | } else if err = os.WriteFile(filePath, []byte(content), 0o600); err != nil { |
| 273 | return nil, errors.Newf("write file: %v", err) |
| 274 | } |
| 275 | |
| 276 | // 🚨 SECURITY: Prevent including unintended options in the path to the Git command. |
| 277 | cmd := exec.Command("git", "diff", "--end-of-options", treePath) |
| 278 | cmd.Dir = localPath |
| 279 | cmd.Stderr = os.Stderr |
| 280 | |
| 281 | stdout, err := cmd.StdoutPipe() |
| 282 | if err != nil { |
| 283 | return nil, errors.Newf("get stdout pipe: %v", err) |
| 284 | } |
| 285 | |
| 286 | if err = cmd.Start(); err != nil { |
| 287 | return nil, errors.Newf("start: %v", err) |
| 288 | } |
| 289 | |
| 290 | pid := process.Add(fmt.Sprintf("GetDiffPreview [repo_path: %s]", r.RepoPath()), cmd) |
| 291 | defer process.Remove(pid) |
| 292 | |
| 293 | diff, err := gitutil.ParseDiff(stdout, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars) |
| 294 | if err != nil { |
| 295 | return nil, errors.Newf("parse diff: %v", err) |
| 296 | } |
| 297 | if err = cmd.Wait(); err != nil { |
| 298 | return nil, errors.Newf("wait: %v", err) |
| 299 | } |
| 300 | return diff, nil |
| 301 | } |
| 302 | |
| 303 | // ________ .__ __ ___________.__.__ |
no test coverage detected