1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.SvnHooks
18 using System
.Collections
;
19 using System
.Configuration
;
20 using System
.Diagnostics
;
21 using System
.Text
.RegularExpressions
;
23 using Castle
.MicroKernel
;
25 using Castle
.Windsor
.Configuration
.Interpreters
;
26 using Castle
.Windsor
.Configuration
.Sources
;
28 using Castle
.SvnHooks
;
31 /// Summary description for Application.
33 public class Application
36 private static bool HooksAllow(RepositoryFile file
, IPreCommit
[] hooks
)
39 foreach (IPreCommit hook
in hooks
)
41 Error
[] errors
= hook
.PreCommit(file
);
42 if(errors
!= null && errors
.Length
> 0)
45 Console
.Error
.WriteLine("An error occured in \"{0}\"", file
);
46 foreach(Error error
in errors
)
48 Console
.Error
.WriteLine(error
.Description
);
56 private static IPreCommit
[] FetchHooks(IKernel kernel
)
58 ArrayList list
= new ArrayList();
59 foreach (IHandler handler
in kernel
.GetHandlers(typeof(IPreCommit
)))
61 IPreCommit hook
= (IPreCommit
)handler
.Resolve();
65 return (IPreCommit
[])list
.ToArray(typeof(IPreCommit
));
69 /// The main entry point for the application.
72 static int Main(string[] args
)
76 // Fetch paths and transaction from configuration and arguments
77 String svnlookPath
= ConfigurationSettings
.AppSettings
["svnlook.location"];
78 String repositoryPath
= args
[0];
79 String transactionString
= args
[1];
80 Transaction transaction
= Transaction
.Parse(transactionString
);
82 // Initialize a WindsorContainer with all the relevant hooks
84 WindsorContainer container
= new WindsorContainer(new XmlInterpreter(new AppDomainConfigSource("castle")));
85 IRepository repository
= new DefaultRepository(
90 container
.Kernel
.AddComponentInstance("Repository", typeof(IRepository
), repository
);
92 // Fetch all the hooks from the container, if we get none
93 // we dont need to process the files in the transaction
94 // and can simply exit the program with success at this point.
95 IPreCommit
[] hooks
= FetchHooks(container
.Kernel
);
97 if (hooks
.Length
== 0)
100 // Start processing all the files commited and run the hooks
101 // on them. This is done by executing a changed command on
102 // svnlook and parsing the result for the files/directories.
104 Regex lineRegex
= new Regex("^(?<contents>[AUD_])(?<properties>[U ]) +(?<file>[^ ].*) *$");
105 SvnLook svnLook
= new SvnLook(svnlookPath
, repositoryPath
);
106 using(Process process
= svnLook
.Execute(SvnLookCommand
.Changed
, transaction
, null))
109 while((line
= process
.StandardOutput
.ReadLine()) != null)
111 Match m
= lineRegex
.Match(line
);
115 Console
.Error
.WriteLine("Could not match line: " + line
);
119 if(m
.Groups
["file"].Value
.EndsWith("/"))
121 // This is a directory, not a file.
123 // TODO: Add directory handling
127 RepositoryStatus contentsStatus
;
128 RepositoryStatus propertiesStatus
;
130 switch (m
.Groups
["contents"].Value
)
133 contentsStatus
= RepositoryStatus
.Added
;
136 contentsStatus
= RepositoryStatus
.Updated
;
139 contentsStatus
= RepositoryStatus
.Deleted
;
142 contentsStatus
= RepositoryStatus
.Unchanged
;
145 Console
.Error
.WriteLine("Could not match status flags for contents on line: " + line
);
148 switch (m
.Groups
["properties"].Value
)
151 propertiesStatus
= RepositoryStatus
.Updated
;
154 propertiesStatus
= RepositoryStatus
.Unchanged
;
157 Console
.Error
.WriteLine("Could not match status flags for properties on line: " + line
);
161 using(RepositoryFile file
= new RepositoryFile(repository
, m
.Groups
["file"].Value
, contentsStatus
, propertiesStatus
))
164 // If HooksAllow returns false we should not allow
165 // the transaction, but rather than exiting we store
166 // that fact in a boolean so that the user will be
167 // told all errors his files contain rather than just
170 hooksOK
&= HooksAllow(file
, hooks
);
187 Console
.Error
.WriteLine("An uncaught exception was thrown in the hook implementation");
188 Console
.Error
.WriteLine(e
.Message
);