44 "context"
55 "errors"
66 "fmt"
7+ "io/fs"
78 "os"
89 "os/exec"
910 "path/filepath"
@@ -17,9 +18,9 @@ import (
1718)
1819
1920// setupRepo must be called from Run
20- // ex.jobWorkingDir must be already set
21- // TODO: change ownership to uid:gid
21+ // Must be called after setJobWorkingDir and setJobCredentials
2222func (ex * RunExecutor ) setupRepo (ctx context.Context ) error {
23+ log .Trace (ctx , "Setting up repo" )
2324 if ex .jobWorkingDir == "" {
2425 return errors .New ("setup repo: working dir is not set" )
2526 }
@@ -37,7 +38,7 @@ func (ex *RunExecutor) setupRepo(ctx context.Context) error {
3738 }
3839 log .Trace (ctx , "Job repo dir" , "path" , ex .repoDir )
3940
40- repoDirIsEmpty , err := ex .prepareRepoDir (ctx )
41+ repoDirIsEmpty , repoDirMustBeMoved , err := ex .checkRepoDir (ctx )
4142 if err != nil {
4243 return fmt .Errorf ("prepare repo dir: %w" , err )
4344 }
@@ -59,23 +60,27 @@ func (ex *RunExecutor) setupRepo(ctx context.Context) error {
5960 return fmt .Errorf ("setup repo: unsupported action: %s" , repoExistsAction )
6061 }
6162 }
62- // Move existing repo files from the repo dir and back to be able to git clone.
63- // Currently, only needed for volumes mounted inside repo with lost+found present.
64- tmpRepoDir , err := os .MkdirTemp (ex .tempDir , "repo_dir_copy" )
65- if err != nil {
66- return fmt .Errorf ("create temp repo dir: %w" , err )
67- }
68- defer func () { _ = os .RemoveAll (tmpRepoDir ) }()
69- err = ex .moveRepoDir (tmpRepoDir )
70- if err != nil {
71- return fmt .Errorf ("move repo dir: %w" , err )
72- }
73- defer func () {
74- err_ := ex .restoreRepoDir (tmpRepoDir )
75- if err == nil {
76- err = fmt .Errorf ("restore repo dir: %w" , err_ )
63+
64+ if repoDirMustBeMoved {
65+ // Move existing repo files from the repo dir and back to be able to git clone.
66+ // Currently, only needed for volumes mounted inside repo with lost+found present.
67+ tmpRepoDir , err := os .MkdirTemp (ex .tempDir , "repo_dir_copy" )
68+ if err != nil {
69+ return fmt .Errorf ("create temp repo dir: %w" , err )
70+ }
71+ defer func () { _ = os .RemoveAll (tmpRepoDir ) }()
72+ err = ex .moveRepoDir (ctx , tmpRepoDir )
73+ if err != nil {
74+ return fmt .Errorf ("move repo dir: %w" , err )
7775 }
78- }()
76+ defer func () {
77+ err_ := ex .restoreRepoDir (ctx , tmpRepoDir )
78+ if err == nil {
79+ err = fmt .Errorf ("restore repo dir: %w" , err_ )
80+ }
81+ }()
82+ }
83+
7984 switch ex .getRepoData ().RepoType {
8085 case "remote" :
8186 log .Trace (ctx , "Fetching git repository" )
@@ -90,6 +95,11 @@ func (ex *RunExecutor) setupRepo(ctx context.Context) error {
9095 default :
9196 return fmt .Errorf ("unknown RepoType: %s" , ex .getRepoData ().RepoType )
9297 }
98+
99+ if err := ex .chownRepoDir (ctx ); err != nil {
100+ return fmt .Errorf ("chown repo dir: %w" , err )
101+ }
102+
93103 return err
94104}
95105
@@ -125,7 +135,7 @@ func (ex *RunExecutor) prepareGit(ctx context.Context) error {
125135 }
126136
127137 log .Trace (ctx , "Checking out remote repo" , "GIT URL" , repoManager .URL ())
128- if err := repoManager .Checkout (); err != nil {
138+ if err := repoManager .Checkout (ctx ); err != nil {
129139 return fmt .Errorf ("checkout repo: %w" , err )
130140 }
131141 if err := repoManager .SetConfig (ex .getRepoData ().RepoConfigName , ex .getRepoData ().RepoConfigEmail ); err != nil {
@@ -158,56 +168,74 @@ func (ex *RunExecutor) prepareArchive(ctx context.Context) error {
158168 return nil
159169}
160170
161- func (ex * RunExecutor ) prepareRepoDir (ctx context.Context ) (bool , error ) {
162- log .Trace (ctx , "Preparing repo dir" )
171+ func (ex * RunExecutor ) checkRepoDir (ctx context.Context ) (isEmpty bool , mustBeMoved bool , err error ) {
172+ log .Trace (ctx , "Checking repo dir" )
163173 info , err := os .Stat (ex .repoDir )
164174 if err != nil {
165175 if errors .Is (err , os .ErrNotExist ) {
166- if err = common .MkdirAll (ctx , ex .repoDir , ex .jobUid , ex .jobGid ); err != nil {
167- return false , fmt .Errorf ("create repo dir: %w" , err )
168- }
169- // No repo dir - created a new one
170- return true , nil
176+ // No repo dir
177+ return true , false , nil
171178 }
172- return false , fmt .Errorf ("stat repo dir: %w" , err )
179+ return false , false , fmt .Errorf ("stat repo dir: %w" , err )
173180 }
174181 if ! info .IsDir () {
175- return false , fmt .Errorf ("stat repo dir: %s is not a dir" , ex .repoDir )
182+ return false , false , fmt .Errorf ("stat repo dir: %s is not a dir" , ex .repoDir )
176183 }
177184 entries , err := os .ReadDir (ex .repoDir )
178185 if err != nil {
179- return false , fmt .Errorf ("read repo dir: %w" , err )
186+ return false , false , fmt .Errorf ("read repo dir: %w" , err )
180187 }
181188 if len (entries ) == 0 {
182189 // Repo dir is empty
183- return true , nil
190+ return true , false , nil
184191 }
185192 if len (entries ) == 1 && entries [0 ].Name () == "lost+found" {
186193 // lost+found may be present on a newly created volume
187- // We (but not Git, see `{move,restore}RepoDir` ) consider such a dir "empty"
188- return true , nil
194+ // We (but not Git, thus mustBeMoved = true ) consider such a dir "empty"
195+ return true , true , nil
189196 }
190197 // Repo dir is not empty
191- return false , nil
198+ return false , false , nil
192199}
193200
194- func (ex * RunExecutor ) moveRepoDir (tmpDir string ) error {
195- if err := moveDir (ex .repoDir , tmpDir ); err != nil {
201+ func (ex * RunExecutor ) moveRepoDir (ctx context. Context , tmpDir string ) error {
202+ if err := moveDir (ctx , ex .repoDir , tmpDir ); err != nil {
196203 return fmt .Errorf ("move directory: %w" , err )
197204 }
198205 return nil
199206}
200207
201- func (ex * RunExecutor ) restoreRepoDir (tmpDir string ) error {
202- if err := moveDir (tmpDir , ex .repoDir ); err != nil {
208+ func (ex * RunExecutor ) restoreRepoDir (ctx context. Context , tmpDir string ) error {
209+ if err := moveDir (ctx , tmpDir , ex .repoDir ); err != nil {
203210 return fmt .Errorf ("move directory: %w" , err )
204211 }
205212 return nil
206213}
207214
208- func moveDir (srcDir , dstDir string ) error {
215+ func (ex * RunExecutor ) chownRepoDir (ctx context.Context ) error {
216+ log .Trace (ctx , "Chowning repo dir" )
217+ if ex .jobUid == - 1 && ex .jobGid == - 1 {
218+ return nil
219+ }
220+ return filepath .WalkDir (
221+ ex .repoDir ,
222+ func (p string , d fs.DirEntry , err error ) error {
223+ // We consider walk/chown errors non-fatal
224+ if err != nil {
225+ log .Debug (ctx , "Error while walking repo dir" , "path" , p , "err" , err )
226+ return nil
227+ }
228+ if err := os .Chown (p , ex .jobUid , ex .jobGid ); err != nil {
229+ log .Debug (ctx , "Error while chowning repo dir" , "path" , p , "err" , err )
230+ }
231+ return nil
232+ },
233+ )
234+ }
235+
236+ func moveDir (ctx context.Context , srcDir , dstDir string ) error {
209237 // We cannot just move/rename files because with volumes they'll be on different devices
210- cmd := exec .CommandContext (context . TODO () , "cp" , "-a" , srcDir + "/." , dstDir )
238+ cmd := exec .CommandContext (ctx , "cp" , "-a" , srcDir + "/." , dstDir )
211239 if output , err := cmd .CombinedOutput (); err != nil {
212240 return fmt .Errorf ("failed to cp: %w, output: %s" , err , string (output ))
213241 }
0 commit comments