Show More
@@ -1,18 +1,24 b'' | |||||
1 | Pylons based replacement for hgwebdir. Fully customizable, |
|
1 | Pylons based replacement for hgwebdir. Fully customizable, | |
2 | with authentication, permissions. Based on vcs library. |
|
2 | with authentication, permissions. Based on vcs library. | |
3 | - has it's own middleware to handle mercurial protocol request each request can |
|
3 | - has it's own middleware to handle mercurial protocol request each request can | |
4 | be logged and authenticated +threaded performance unlikely to hgweb |
|
4 | be logged and authenticated +threaded performance unlikely to hgweb | |
5 | - mako templates let's you cusmotize look and feel of appplication. |
|
5 | - mako templates let's you cusmotize look and feel of appplication. | |
6 | - diffs annotations and source code all colored by pygments. |
|
6 | - diffs annotations and source code all colored by pygments. | |
7 | - admin interface for performing user/permission managments as well as repository |
|
7 | - admin interface for performing user/permission managments as well as repository | |
8 | managment |
|
8 | managment | |
9 | - added cache with invalidation on push/repo managment for high performance and |
|
9 | - added cache with invalidation on push/repo managment for high performance and | |
10 | always upto date data. |
|
10 | always upto date data. | |
11 | - rss /atom feed customizable |
|
11 | - rss /atom feed customizable | |
12 | - future support for git |
|
12 | - future support for git | |
13 | - based on pylons 1.0 / sqlalchemy 0.6 |
|
13 | - based on pylons 1.0 / sqlalchemy 0.6 | |
14 |
|
14 | |||
15 | === |
|
15 | === | |
16 | This software is still in beta mode. I don't guarantee that it'll work. |
|
16 | This software is still in beta mode. I don't guarantee that it'll work. | |
17 | I started this project since i was tired of sad looks, and zero controll over |
|
17 | I started this project since i was tired of sad looks, and zero controll over | |
18 | our company regular hgwebdir. |
|
18 | our company regular hgwebdir. | |
|
19 | ||||
|
20 | ||||
|
21 | == INSTALATION | |||
|
22 | run dbmanage.py from pylons_app/lib it should create all needed table and | |||
|
23 | an admin account, Edit file repositories.config and change the path for you | |||
|
24 | mercurial repositories, remember about permissions. No newline at end of file |
@@ -1,135 +1,136 b'' | |||||
1 | ################################################################################ |
|
1 | ################################################################################ | |
2 | ################################################################################ |
|
2 | ################################################################################ | |
3 | # pylons_app - Pylons environment configuration # |
|
3 | # pylons_app - Pylons environment configuration # | |
4 | # # |
|
4 | # # | |
5 | # The %(here)s variable will be replaced with the parent directory of this file# |
|
5 | # The %(here)s variable will be replaced with the parent directory of this file# | |
6 | ################################################################################ |
|
6 | ################################################################################ | |
7 |
|
7 | |||
8 | [DEFAULT] |
|
8 | [DEFAULT] | |
9 | debug = true |
|
9 | debug = true | |
10 | ############################################ |
|
10 | ############################################ | |
11 | ## Uncomment and replace with the address ## |
|
11 | ## Uncomment and replace with the address ## | |
12 | ## which should receive any error reports ## |
|
12 | ## which should receive any error reports ## | |
13 | ############################################ |
|
13 | ############################################ | |
14 | #email_to = marcin.kuzminski@etelko.pl |
|
14 | #email_to = marcin.kuzminski@etelko.pl | |
15 | #smtp_server = mail.etelko.pl |
|
15 | #smtp_server = mail.etelko.pl | |
16 | #error_email_from = paste_error@localhost |
|
16 | #error_email_from = paste_error@localhost | |
17 | #smtp_username = |
|
17 | #smtp_username = | |
18 | #smtp_password = |
|
18 | #smtp_password = | |
19 | #error_message = 'mercurial crash !' |
|
19 | #error_message = 'mercurial crash !' | |
20 |
|
20 | |||
21 | [server:main] |
|
21 | [server:main] | |
22 | ##nr of threads to spawn |
|
22 | ##nr of threads to spawn | |
23 | threadpool_workers = 5 |
|
23 | threadpool_workers = 5 | |
24 |
|
24 | |||
25 | ##max request before |
|
25 | ##max request before | |
26 | threadpool_max_requests = 2 |
|
26 | threadpool_max_requests = 2 | |
27 |
|
27 | |||
28 | ##option to use threads of process |
|
28 | ##option to use threads of process | |
29 | use_threadpool = true |
|
29 | use_threadpool = true | |
30 |
|
30 | |||
31 | use = egg:Paste#http |
|
31 | use = egg:Paste#http | |
32 | host = 127.0.0.1 |
|
32 | host = 127.0.0.1 | |
33 | port = 5000 |
|
33 | port = 5000 | |
34 |
|
34 | |||
35 | [app:main] |
|
35 | [app:main] | |
36 | use = egg:pylons_app |
|
36 | use = egg:pylons_app | |
37 | full_stack = true |
|
37 | full_stack = true | |
38 | static_files = false |
|
38 | static_files = false | |
39 | lang=en |
|
39 | lang=en | |
40 | cache_dir = %(here)s/data |
|
40 | cache_dir = %(here)s/data | |
41 | ##a name for our application |
|
41 | ##a name for our application | |
42 | hg_app_name = Python-works |
|
42 | hg_app_name = Python-works | |
|
43 | hg_app_repo_conf = repositories.config | |||
43 |
|
44 | |||
44 | #################################### |
|
45 | #################################### | |
45 | ### BEAKER CACHE #### |
|
46 | ### BEAKER CACHE #### | |
46 | #################################### |
|
47 | #################################### | |
47 | beaker.cache.data_dir=/tmp/cache/data |
|
48 | beaker.cache.data_dir=/tmp/cache/data | |
48 | beaker.cache.lock_dir=/tmp/cache/lock |
|
49 | beaker.cache.lock_dir=/tmp/cache/lock | |
49 | beaker.cache.regions=short_term,long_term |
|
50 | beaker.cache.regions=short_term,long_term | |
50 | beaker.cache.long_term.type=memory |
|
51 | beaker.cache.long_term.type=memory | |
51 | beaker.cache.long_term.expire=36000 |
|
52 | beaker.cache.long_term.expire=36000 | |
52 | beaker.cache.short_term.type=memory |
|
53 | beaker.cache.short_term.type=memory | |
53 | beaker.cache.short_term.expire=60 |
|
54 | beaker.cache.short_term.expire=60 | |
54 |
|
55 | |||
55 | ################################################################################ |
|
56 | ################################################################################ | |
56 | ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## |
|
57 | ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## | |
57 | ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## |
|
58 | ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## | |
58 | ## execute malicious code after an exception is raised. ## |
|
59 | ## execute malicious code after an exception is raised. ## | |
59 | ################################################################################ |
|
60 | ################################################################################ | |
60 | #set debug = false |
|
61 | #set debug = false | |
61 |
|
62 | |||
62 | ################################## |
|
63 | ################################## | |
63 | ### LOGVIEW CONFIG ### |
|
64 | ### LOGVIEW CONFIG ### | |
64 | ################################## |
|
65 | ################################## | |
65 | logview.sqlalchemy = #faa |
|
66 | logview.sqlalchemy = #faa | |
66 | logview.pylons.templating = #bfb |
|
67 | logview.pylons.templating = #bfb | |
67 | logview.pylons.util = #eee |
|
68 | logview.pylons.util = #eee | |
68 |
|
69 | |||
69 | ######################################################### |
|
70 | ######################################################### | |
70 | ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### |
|
71 | ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### | |
71 | ######################################################### |
|
72 | ######################################################### | |
72 | sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db |
|
73 | sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db | |
73 | #sqlalchemy.db1.echo = False |
|
74 | #sqlalchemy.db1.echo = False | |
74 | #sqlalchemy.db1.pool_recycle = 3600 |
|
75 | #sqlalchemy.db1.pool_recycle = 3600 | |
75 | sqlalchemy.convert_unicode = true |
|
76 | sqlalchemy.convert_unicode = true | |
76 |
|
77 | |||
77 | ################################ |
|
78 | ################################ | |
78 | ### LOGGING CONFIGURATION #### |
|
79 | ### LOGGING CONFIGURATION #### | |
79 | ################################ |
|
80 | ################################ | |
80 | [loggers] |
|
81 | [loggers] | |
81 | keys = root, routes, pylons_app, sqlalchemy |
|
82 | keys = root, routes, pylons_app, sqlalchemy | |
82 |
|
83 | |||
83 | [handlers] |
|
84 | [handlers] | |
84 | keys = console |
|
85 | keys = console | |
85 |
|
86 | |||
86 | [formatters] |
|
87 | [formatters] | |
87 | keys = generic,color_formatter |
|
88 | keys = generic,color_formatter | |
88 |
|
89 | |||
89 | ############# |
|
90 | ############# | |
90 | ## LOGGERS ## |
|
91 | ## LOGGERS ## | |
91 | ############# |
|
92 | ############# | |
92 | [logger_root] |
|
93 | [logger_root] | |
93 | level = NOTSET |
|
94 | level = NOTSET | |
94 | handlers = console |
|
95 | handlers = console | |
95 |
|
96 | |||
96 | [logger_routes] |
|
97 | [logger_routes] | |
97 | level = DEBUG |
|
98 | level = DEBUG | |
98 | handlers = console |
|
99 | handlers = console | |
99 | qualname = routes.middleware |
|
100 | qualname = routes.middleware | |
100 | # "level = DEBUG" logs the route matched and routing variables. |
|
101 | # "level = DEBUG" logs the route matched and routing variables. | |
101 |
|
102 | |||
102 | [logger_pylons_app] |
|
103 | [logger_pylons_app] | |
103 | level = DEBUG |
|
104 | level = DEBUG | |
104 | handlers = console |
|
105 | handlers = console | |
105 | qualname = pylons_app |
|
106 | qualname = pylons_app | |
106 | propagate = 0 |
|
107 | propagate = 0 | |
107 |
|
108 | |||
108 | [logger_sqlalchemy] |
|
109 | [logger_sqlalchemy] | |
109 | level = ERROR |
|
110 | level = ERROR | |
110 | handlers = console |
|
111 | handlers = console | |
111 | qualname = sqlalchemy.engine |
|
112 | qualname = sqlalchemy.engine | |
112 | propagate = 0 |
|
113 | propagate = 0 | |
113 |
|
114 | |||
114 | ############## |
|
115 | ############## | |
115 | ## HANDLERS ## |
|
116 | ## HANDLERS ## | |
116 | ############## |
|
117 | ############## | |
117 |
|
118 | |||
118 | [handler_console] |
|
119 | [handler_console] | |
119 | class = StreamHandler |
|
120 | class = StreamHandler | |
120 | args = (sys.stderr,) |
|
121 | args = (sys.stderr,) | |
121 | level = NOTSET |
|
122 | level = NOTSET | |
122 | formatter = color_formatter |
|
123 | formatter = color_formatter | |
123 |
|
124 | |||
124 | ################ |
|
125 | ################ | |
125 | ## FORMATTERS ## |
|
126 | ## FORMATTERS ## | |
126 | ################ |
|
127 | ################ | |
127 |
|
128 | |||
128 | [formatter_generic] |
|
129 | [formatter_generic] | |
129 | format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
130 | format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s | |
130 | datefmt = %Y-%m-%d %H:%M:%S |
|
131 | datefmt = %Y-%m-%d %H:%M:%S | |
131 |
|
132 | |||
132 | [formatter_color_formatter] |
|
133 | [formatter_color_formatter] | |
133 | class=pylons_app.lib.colored_formatter.ColorFormatter |
|
134 | class=pylons_app.lib.colored_formatter.ColorFormatter | |
134 | format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
135 | format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s | |
135 | datefmt = %Y-%m-%d %H:%M:%S No newline at end of file |
|
136 | datefmt = %Y-%m-%d %H:%M:%S |
@@ -1,135 +1,136 b'' | |||||
1 | ################################################################################ |
|
1 | ################################################################################ | |
2 | ################################################################################ |
|
2 | ################################################################################ | |
3 | # pylons_app - Pylons environment configuration # |
|
3 | # pylons_app - Pylons environment configuration # | |
4 | # # |
|
4 | # # | |
5 | # The %(here)s variable will be replaced with the parent directory of this file# |
|
5 | # The %(here)s variable will be replaced with the parent directory of this file# | |
6 | ################################################################################ |
|
6 | ################################################################################ | |
7 |
|
7 | |||
8 | [DEFAULT] |
|
8 | [DEFAULT] | |
9 | debug = true |
|
9 | debug = true | |
10 | ############################################ |
|
10 | ############################################ | |
11 | ## Uncomment and replace with the address ## |
|
11 | ## Uncomment and replace with the address ## | |
12 | ## which should receive any error reports ## |
|
12 | ## which should receive any error reports ## | |
13 | ############################################ |
|
13 | ############################################ | |
14 | #email_to = marcin.kuzminski@etelko.pl |
|
14 | #email_to = marcin.kuzminski@etelko.pl | |
15 | #smtp_server = mail.etelko.pl |
|
15 | #smtp_server = mail.etelko.pl | |
16 | #error_email_from = paste_error@localhost |
|
16 | #error_email_from = paste_error@localhost | |
17 | #smtp_username = |
|
17 | #smtp_username = | |
18 | #smtp_password = |
|
18 | #smtp_password = | |
19 | #error_message = 'mercurial crash !' |
|
19 | #error_message = 'mercurial crash !' | |
20 |
|
20 | |||
21 | [server:main] |
|
21 | [server:main] | |
22 | ##nr of threads to spawn |
|
22 | ##nr of threads to spawn | |
23 | threadpool_workers = 5 |
|
23 | threadpool_workers = 5 | |
24 |
|
24 | |||
25 | ##max request before |
|
25 | ##max request before | |
26 | threadpool_max_requests = 2 |
|
26 | threadpool_max_requests = 2 | |
27 |
|
27 | |||
28 | ##option to use threads of process |
|
28 | ##option to use threads of process | |
29 | use_threadpool = true |
|
29 | use_threadpool = true | |
30 |
|
30 | |||
31 | use = egg:Paste#http |
|
31 | use = egg:Paste#http | |
32 | host = 127.0.0.1 |
|
32 | host = 127.0.0.1 | |
33 | port = 8001 |
|
33 | port = 8001 | |
34 |
|
34 | |||
35 | [app:main] |
|
35 | [app:main] | |
36 | use = egg:pylons_app |
|
36 | use = egg:pylons_app | |
37 | full_stack = true |
|
37 | full_stack = true | |
38 | static_files = false |
|
38 | static_files = false | |
39 | lang=en |
|
39 | lang=en | |
40 | cache_dir = %(here)s/data |
|
40 | cache_dir = %(here)s/data | |
41 | ##a name for our application |
|
41 | ##a name for our application | |
42 | hg_app_name = Python-works |
|
42 | hg_app_name = Python-works | |
|
43 | hg_app_repo_conf = repositories.config | |||
43 |
|
44 | |||
44 | #################################### |
|
45 | #################################### | |
45 | ### BEAKER CACHE #### |
|
46 | ### BEAKER CACHE #### | |
46 | #################################### |
|
47 | #################################### | |
47 | beaker.cache.data_dir=/tmp/cache/data |
|
48 | beaker.cache.data_dir=/tmp/cache/data | |
48 | beaker.cache.lock_dir=/tmp/cache/lock |
|
49 | beaker.cache.lock_dir=/tmp/cache/lock | |
49 | beaker.cache.regions=short_term,long_term |
|
50 | beaker.cache.regions=short_term,long_term | |
50 | beaker.cache.long_term.type=memory |
|
51 | beaker.cache.long_term.type=memory | |
51 | beaker.cache.long_term.expire=36000 |
|
52 | beaker.cache.long_term.expire=36000 | |
52 | beaker.cache.short_term.type=memory |
|
53 | beaker.cache.short_term.type=memory | |
53 | beaker.cache.short_term.expire=60 |
|
54 | beaker.cache.short_term.expire=60 | |
54 |
|
55 | |||
55 | ################################################################################ |
|
56 | ################################################################################ | |
56 | ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## |
|
57 | ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ## | |
57 | ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## |
|
58 | ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ## | |
58 | ## execute malicious code after an exception is raised. ## |
|
59 | ## execute malicious code after an exception is raised. ## | |
59 | ################################################################################ |
|
60 | ################################################################################ | |
60 | set debug = false |
|
61 | set debug = false | |
61 |
|
62 | |||
62 | ################################## |
|
63 | ################################## | |
63 | ### LOGVIEW CONFIG ### |
|
64 | ### LOGVIEW CONFIG ### | |
64 | ################################## |
|
65 | ################################## | |
65 | logview.sqlalchemy = #faa |
|
66 | logview.sqlalchemy = #faa | |
66 | logview.pylons.templating = #bfb |
|
67 | logview.pylons.templating = #bfb | |
67 | logview.pylons.util = #eee |
|
68 | logview.pylons.util = #eee | |
68 |
|
69 | |||
69 | ######################################################### |
|
70 | ######################################################### | |
70 | ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### |
|
71 | ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### | |
71 | ######################################################### |
|
72 | ######################################################### | |
72 | sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db |
|
73 | sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db | |
73 | #sqlalchemy.db1.echo = False |
|
74 | #sqlalchemy.db1.echo = False | |
74 | #sqlalchemy.db1.pool_recycle = 3600 |
|
75 | #sqlalchemy.db1.pool_recycle = 3600 | |
75 | sqlalchemy.convert_unicode = true |
|
76 | sqlalchemy.convert_unicode = true | |
76 |
|
77 | |||
77 | ################################ |
|
78 | ################################ | |
78 | ### LOGGING CONFIGURATION #### |
|
79 | ### LOGGING CONFIGURATION #### | |
79 | ################################ |
|
80 | ################################ | |
80 | [loggers] |
|
81 | [loggers] | |
81 | keys = root, routes, pylons_app, sqlalchemy |
|
82 | keys = root, routes, pylons_app, sqlalchemy | |
82 |
|
83 | |||
83 | [handlers] |
|
84 | [handlers] | |
84 | keys = console |
|
85 | keys = console | |
85 |
|
86 | |||
86 | [formatters] |
|
87 | [formatters] | |
87 | keys = generic,color_formatter |
|
88 | keys = generic,color_formatter | |
88 |
|
89 | |||
89 | ############# |
|
90 | ############# | |
90 | ## LOGGERS ## |
|
91 | ## LOGGERS ## | |
91 | ############# |
|
92 | ############# | |
92 | [logger_root] |
|
93 | [logger_root] | |
93 | level = INFO |
|
94 | level = INFO | |
94 | handlers = console |
|
95 | handlers = console | |
95 |
|
96 | |||
96 | [logger_routes] |
|
97 | [logger_routes] | |
97 | level = INFO |
|
98 | level = INFO | |
98 | handlers = console |
|
99 | handlers = console | |
99 | qualname = routes.middleware |
|
100 | qualname = routes.middleware | |
100 | # "level = DEBUG" logs the route matched and routing variables. |
|
101 | # "level = DEBUG" logs the route matched and routing variables. | |
101 |
|
102 | |||
102 | [logger_pylons_app] |
|
103 | [logger_pylons_app] | |
103 | level = DEBUG |
|
104 | level = DEBUG | |
104 | handlers = console |
|
105 | handlers = console | |
105 | qualname = pylons_app |
|
106 | qualname = pylons_app | |
106 | propagate = 0 |
|
107 | propagate = 0 | |
107 |
|
108 | |||
108 | [logger_sqlalchemy] |
|
109 | [logger_sqlalchemy] | |
109 | level = ERROR |
|
110 | level = ERROR | |
110 | handlers = console |
|
111 | handlers = console | |
111 | qualname = sqlalchemy.engine |
|
112 | qualname = sqlalchemy.engine | |
112 | propagate = 0 |
|
113 | propagate = 0 | |
113 |
|
114 | |||
114 | ############## |
|
115 | ############## | |
115 | ## HANDLERS ## |
|
116 | ## HANDLERS ## | |
116 | ############## |
|
117 | ############## | |
117 |
|
118 | |||
118 | [handler_console] |
|
119 | [handler_console] | |
119 | class = StreamHandler |
|
120 | class = StreamHandler | |
120 | args = (sys.stderr,) |
|
121 | args = (sys.stderr,) | |
121 | level = NOTSET |
|
122 | level = NOTSET | |
122 | formatter = color_formatter |
|
123 | formatter = color_formatter | |
123 |
|
124 | |||
124 | ################ |
|
125 | ################ | |
125 | ## FORMATTERS ## |
|
126 | ## FORMATTERS ## | |
126 | ################ |
|
127 | ################ | |
127 |
|
128 | |||
128 | [formatter_generic] |
|
129 | [formatter_generic] | |
129 | format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
130 | format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s | |
130 | datefmt = %Y-%m-%d %H:%M:%S |
|
131 | datefmt = %Y-%m-%d %H:%M:%S | |
131 |
|
132 | |||
132 | [formatter_color_formatter] |
|
133 | [formatter_color_formatter] | |
133 | class=pylons_app.lib.colored_formatter.ColorFormatter |
|
134 | class=pylons_app.lib.colored_formatter.ColorFormatter | |
134 | format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
135 | format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s | |
135 | datefmt = %Y-%m-%d %H:%M:%S No newline at end of file |
|
136 | datefmt = %Y-%m-%d %H:%M:%S |
@@ -1,25 +1,25 b'' | |||||
1 | """The application's Globals object""" |
|
1 | """The application's Globals object""" | |
2 |
|
2 | |||
3 | from beaker.cache import CacheManager |
|
3 | from beaker.cache import CacheManager | |
4 | from beaker.util import parse_cache_config_options |
|
4 | from beaker.util import parse_cache_config_options | |
5 | from pylons_app.lib.utils import make_ui |
|
5 | from pylons_app.lib.utils import make_ui | |
6 |
|
6 | |||
7 | class Globals(object): |
|
7 | class Globals(object): | |
8 |
|
8 | |||
9 | """Globals acts as a container for objects available throughout the |
|
9 | """Globals acts as a container for objects available throughout the | |
10 | life of the application |
|
10 | life of the application | |
11 |
|
11 | |||
12 | """ |
|
12 | """ | |
13 |
|
13 | |||
14 | def __init__(self, config): |
|
14 | def __init__(self, config): | |
15 | """One instance of Globals is created during application |
|
15 | """One instance of Globals is created during application | |
16 | initialization and is available during requests via the |
|
16 | initialization and is available during requests via the | |
17 | 'app_globals' variable |
|
17 | 'app_globals' variable | |
18 |
|
18 | |||
19 | """ |
|
19 | """ | |
20 | self.cache = CacheManager(**parse_cache_config_options(config)) |
|
20 | self.cache = CacheManager(**parse_cache_config_options(config)) | |
21 |
self.baseui = make_ui('hg |
|
21 | self.baseui = make_ui(config['hg_app_repo_conf']) | |
22 | self.paths = self.baseui.configitems('paths') |
|
22 | self.paths = self.baseui.configitems('paths') | |
23 | self.base_path = self.paths[0][1].replace('*', '') |
|
23 | self.base_path = self.paths[0][1].replace('*', '') | |
24 | self.changeset_annotation_colors = {} |
|
24 | self.changeset_annotation_colors = {} | |
25 | self.available_permissions = None # propagated after init_model |
|
25 | self.available_permissions = None # propagated after init_model |
@@ -1,88 +1,88 b'' | |||||
1 | '''BACKUP MANAGER''' |
|
1 | '''BACKUP MANAGER''' | |
2 | import logging |
|
2 | import logging | |
3 | from mercurial import config |
|
3 | from mercurial import config | |
4 | import tarfile |
|
4 | import tarfile | |
5 | import os |
|
5 | import os | |
6 | import datetime |
|
6 | import datetime | |
7 | import sys |
|
7 | import sys | |
8 | import subprocess |
|
8 | import subprocess | |
9 | logging.basicConfig(level=logging.DEBUG, |
|
9 | logging.basicConfig(level=logging.DEBUG, | |
10 | format="%(asctime)s %(levelname)-5.5s %(message)s") |
|
10 | format="%(asctime)s %(levelname)-5.5s %(message)s") | |
11 |
|
11 | |||
12 | class BackupManager(object): |
|
12 | class BackupManager(object): | |
13 | def __init__(self): |
|
13 | def __init__(self, id_rsa_path, repo_conf): | |
14 | self.repos_path = None |
|
14 | self.repos_path = None | |
15 | self.backup_file_name = None |
|
15 | self.backup_file_name = None | |
16 |
self.id_rsa_path = |
|
16 | self.id_rsa_path = id_rsa_path | |
17 | self.check_id_rsa() |
|
17 | self.check_id_rsa() | |
18 | cur_dir = os.path.realpath(__file__) |
|
18 | cur_dir = os.path.realpath(__file__) | |
19 | dn = os.path.dirname |
|
19 | dn = os.path.dirname | |
20 | self.backup_file_path = os.path.join(dn(dn(dn(cur_dir))), 'data') |
|
20 | self.backup_file_path = os.path.join(dn(dn(dn(cur_dir))), 'data') | |
21 | cfg = config.config() |
|
21 | cfg = config.config() | |
22 | try: |
|
22 | try: | |
23 |
cfg.read(os.path.join(dn(dn(dn(cur_dir))), |
|
23 | cfg.read(os.path.join(dn(dn(dn(cur_dir))), repo_conf)) | |
24 | except IOError: |
|
24 | except IOError: | |
25 |
logging.error('Could not read |
|
25 | logging.error('Could not read %s', repo_conf) | |
26 | sys.exit() |
|
26 | sys.exit() | |
27 | self.set_repos_path(cfg.items('paths')) |
|
27 | self.set_repos_path(cfg.items('paths')) | |
28 | logging.info('starting backup for %s', self.repos_path) |
|
28 | logging.info('starting backup for %s', self.repos_path) | |
29 | logging.info('backup target %s', self.backup_file_path) |
|
29 | logging.info('backup target %s', self.backup_file_path) | |
30 |
|
30 | |||
31 | if not os.path.isdir(self.repos_path): |
|
31 | if not os.path.isdir(self.repos_path): | |
32 | raise Exception('Not a valid directory in %s' % self.repos_path) |
|
32 | raise Exception('Not a valid directory in %s' % self.repos_path) | |
33 |
|
33 | |||
34 | def check_id_rsa(self): |
|
34 | def check_id_rsa(self): | |
35 | if not os.path.isfile(self.id_rsa_path): |
|
35 | if not os.path.isfile(self.id_rsa_path): | |
36 | logging.error('Could not load id_rsa key file in %s', |
|
36 | logging.error('Could not load id_rsa key file in %s', | |
37 | self.id_rsa_path) |
|
37 | self.id_rsa_path) | |
38 | sys.exit() |
|
38 | sys.exit() | |
39 |
|
39 | |||
40 | def set_repos_path(self, paths): |
|
40 | def set_repos_path(self, paths): | |
41 | repos_path = paths[0][1].split('/') |
|
41 | repos_path = paths[0][1].split('/') | |
42 | if repos_path[-1] in ['*', '**']: |
|
42 | if repos_path[-1] in ['*', '**']: | |
43 | repos_path = repos_path[:-1] |
|
43 | repos_path = repos_path[:-1] | |
44 | if repos_path[0] != '/': |
|
44 | if repos_path[0] != '/': | |
45 | repos_path[0] = '/' |
|
45 | repos_path[0] = '/' | |
46 | self.repos_path = os.path.join(*repos_path) |
|
46 | self.repos_path = os.path.join(*repos_path) | |
47 |
|
47 | |||
48 | def backup_repos(self): |
|
48 | def backup_repos(self): | |
49 | today = datetime.datetime.now().weekday() + 1 |
|
49 | today = datetime.datetime.now().weekday() + 1 | |
50 | self.backup_file_name = "mercurial_repos.%s.tar.gz" % today |
|
50 | self.backup_file_name = "mercurial_repos.%s.tar.gz" % today | |
51 | bckp_file = os.path.join(self.backup_file_path, self.backup_file_name) |
|
51 | bckp_file = os.path.join(self.backup_file_path, self.backup_file_name) | |
52 | tar = tarfile.open(bckp_file, "w:gz") |
|
52 | tar = tarfile.open(bckp_file, "w:gz") | |
53 |
|
53 | |||
54 | for dir_name in os.listdir(self.repos_path): |
|
54 | for dir_name in os.listdir(self.repos_path): | |
55 | logging.info('backing up %s', dir_name) |
|
55 | logging.info('backing up %s', dir_name) | |
56 | tar.add(os.path.join(self.repos_path, dir_name), dir_name) |
|
56 | tar.add(os.path.join(self.repos_path, dir_name), dir_name) | |
57 | tar.close() |
|
57 | tar.close() | |
58 | logging.info('finished backup of mercurial repositories') |
|
58 | logging.info('finished backup of mercurial repositories') | |
59 |
|
59 | |||
60 |
|
60 | |||
61 |
|
61 | |||
62 | def transfer_files(self): |
|
62 | def transfer_files(self): | |
63 | params = { |
|
63 | params = { | |
64 | 'id_rsa_key': self.id_rsa_path, |
|
64 | 'id_rsa_key': self.id_rsa_path, | |
65 | 'backup_file_path':self.backup_file_path, |
|
65 | 'backup_file_path':self.backup_file_path, | |
66 | 'backup_file_name':self.backup_file_name, |
|
66 | 'backup_file_name':self.backup_file_name, | |
67 | } |
|
67 | } | |
68 | cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params, |
|
68 | cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params, | |
69 | '%(backup_file_path)s/%(backup_file_name)s' % params, |
|
69 | '%(backup_file_path)s/%(backup_file_name)s' % params, | |
70 | 'root@192.168.2.102:/backups/mercurial' % params] |
|
70 | 'root@192.168.2.102:/backups/mercurial' % params] | |
71 |
|
71 | |||
72 | subprocess.call(cmd) |
|
72 | subprocess.call(cmd) | |
73 | logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4]) |
|
73 | logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4]) | |
74 |
|
74 | |||
75 |
|
75 | |||
76 | def rm_file(self): |
|
76 | def rm_file(self): | |
77 | logging.info('Removing file %s', self.backup_file_name) |
|
77 | logging.info('Removing file %s', self.backup_file_name) | |
78 | os.remove(os.path.join(self.backup_file_path, self.backup_file_name)) |
|
78 | os.remove(os.path.join(self.backup_file_path, self.backup_file_name)) | |
79 |
|
79 | |||
80 |
|
80 | |||
81 |
|
81 | |||
82 | if __name__ == "__main__": |
|
82 | if __name__ == "__main__": | |
83 | B_MANAGER = BackupManager() |
|
83 | B_MANAGER = BackupManager('/home/pylons/id_rsa', 'repositories.config') | |
84 | B_MANAGER.backup_repos() |
|
84 | B_MANAGER.backup_repos() | |
85 | B_MANAGER.transfer_files() |
|
85 | B_MANAGER.transfer_files() | |
86 | B_MANAGER.rm_file() |
|
86 | B_MANAGER.rm_file() | |
87 |
|
87 | |||
88 |
|
88 |
@@ -1,136 +1,136 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | #!/usr/bin/env python | |
2 | # encoding: utf-8 |
|
2 | # encoding: utf-8 | |
3 | # |
|
3 | # | |
4 | # Copyright (c) 2010 marcink. All rights reserved. |
|
4 | # Copyright (c) 2010 marcink. All rights reserved. | |
5 | # |
|
5 | # | |
6 | """ |
|
6 | """ | |
7 | Created on 2010-04-28 |
|
7 | Created on 2010-04-28 | |
8 |
|
8 | |||
9 | @author: marcink |
|
9 | @author: marcink | |
10 | SimpleHG middleware for handling mercurial protocol request (push/clone etc.) |
|
10 | SimpleHG middleware for handling mercurial protocol request (push/clone etc.) | |
11 | It's implemented with basic auth function |
|
11 | It's implemented with basic auth function | |
12 | """ |
|
12 | """ | |
13 | from datetime import datetime |
|
13 | from datetime import datetime | |
14 | from mercurial.hgweb import hgweb |
|
14 | from mercurial.hgweb import hgweb | |
15 | from mercurial.hgweb.request import wsgiapplication |
|
15 | from mercurial.hgweb.request import wsgiapplication | |
16 | from paste.auth.basic import AuthBasicAuthenticator |
|
16 | from paste.auth.basic import AuthBasicAuthenticator | |
17 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE |
|
17 | from paste.httpheaders import REMOTE_USER, AUTH_TYPE | |
18 | from pylons_app.lib.auth import authfunc |
|
18 | from pylons_app.lib.auth import authfunc | |
19 | from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache |
|
19 | from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache | |
20 | from pylons_app.model import meta |
|
20 | from pylons_app.model import meta | |
21 | from pylons_app.model.db import UserLog, User |
|
21 | from pylons_app.model.db import UserLog, User | |
22 | from webob.exc import HTTPNotFound |
|
22 | from webob.exc import HTTPNotFound | |
23 | import logging |
|
23 | import logging | |
24 | import os |
|
24 | import os | |
25 | log = logging.getLogger(__name__) |
|
25 | log = logging.getLogger(__name__) | |
26 |
|
26 | |||
27 | class SimpleHg(object): |
|
27 | class SimpleHg(object): | |
28 |
|
28 | |||
29 | def __init__(self, application, config): |
|
29 | def __init__(self, application, config): | |
30 | self.application = application |
|
30 | self.application = application | |
31 | self.config = config |
|
31 | self.config = config | |
32 | #authenticate this mercurial request using |
|
32 | #authenticate this mercurial request using | |
33 | realm = '%s %s' % (config['hg_app_name'], 'mercurial repository') |
|
33 | realm = '%s %s' % (config['hg_app_name'], 'mercurial repository') | |
34 | self.authenticate = AuthBasicAuthenticator(realm, authfunc) |
|
34 | self.authenticate = AuthBasicAuthenticator(realm, authfunc) | |
35 |
|
35 | |||
36 | def __call__(self, environ, start_response): |
|
36 | def __call__(self, environ, start_response): | |
37 | if not is_mercurial(environ): |
|
37 | if not is_mercurial(environ): | |
38 | return self.application(environ, start_response) |
|
38 | return self.application(environ, start_response) | |
39 | else: |
|
39 | else: | |
40 | #=================================================================== |
|
40 | #=================================================================== | |
41 | # AUTHENTICATE THIS MERCURIAL REQUEST |
|
41 | # AUTHENTICATE THIS MERCURIAL REQUEST | |
42 | #=================================================================== |
|
42 | #=================================================================== | |
43 | username = REMOTE_USER(environ) |
|
43 | username = REMOTE_USER(environ) | |
44 | if not username: |
|
44 | if not username: | |
45 | result = self.authenticate(environ) |
|
45 | result = self.authenticate(environ) | |
46 | if isinstance(result, str): |
|
46 | if isinstance(result, str): | |
47 | AUTH_TYPE.update(environ, 'basic') |
|
47 | AUTH_TYPE.update(environ, 'basic') | |
48 | REMOTE_USER.update(environ, result) |
|
48 | REMOTE_USER.update(environ, result) | |
49 | else: |
|
49 | else: | |
50 | return result.wsgi_application(environ, start_response) |
|
50 | return result.wsgi_application(environ, start_response) | |
51 |
|
51 | |||
52 | try: |
|
52 | try: | |
53 | repo_name = environ['PATH_INFO'].split('/')[1] |
|
53 | repo_name = environ['PATH_INFO'].split('/')[1] | |
54 | except: |
|
54 | except: | |
55 | return HTTPNotFound()(environ, start_response) |
|
55 | return HTTPNotFound()(environ, start_response) | |
56 |
|
56 | |||
57 | #since we wrap into hgweb, just reset the path |
|
57 | #since we wrap into hgweb, just reset the path | |
58 | environ['PATH_INFO'] = '/' |
|
58 | environ['PATH_INFO'] = '/' | |
59 | self.baseui = make_ui() |
|
59 | self.baseui = make_ui(self.config['hg_app_repo_conf']) | |
60 | self.basepath = self.baseui.configitems('paths')[0][1]\ |
|
60 | self.basepath = self.baseui.configitems('paths')[0][1]\ | |
61 | .replace('*', '') |
|
61 | .replace('*', '') | |
62 | self.repo_path = os.path.join(self.basepath, repo_name) |
|
62 | self.repo_path = os.path.join(self.basepath, repo_name) | |
63 | try: |
|
63 | try: | |
64 | app = wsgiapplication(self.__make_app) |
|
64 | app = wsgiapplication(self.__make_app) | |
65 | except Exception as e: |
|
65 | except Exception as e: | |
66 | return HTTPNotFound()(environ, start_response) |
|
66 | return HTTPNotFound()(environ, start_response) | |
67 | action = self.__get_action(environ) |
|
67 | action = self.__get_action(environ) | |
68 | #invalidate cache on push |
|
68 | #invalidate cache on push | |
69 | if action == 'push': |
|
69 | if action == 'push': | |
70 | self.__invalidate_cache(repo_name) |
|
70 | self.__invalidate_cache(repo_name) | |
71 |
|
71 | |||
72 | if action: |
|
72 | if action: | |
73 | username = self.__get_environ_user(environ) |
|
73 | username = self.__get_environ_user(environ) | |
74 | self.__log_user_action(username, action, repo_name) |
|
74 | self.__log_user_action(username, action, repo_name) | |
75 |
|
75 | |||
76 | return app(environ, start_response) |
|
76 | return app(environ, start_response) | |
77 |
|
77 | |||
78 | def __make_app(self): |
|
78 | def __make_app(self): | |
79 | hgserve = hgweb(self.repo_path) |
|
79 | hgserve = hgweb(self.repo_path) | |
80 | return self.__load_web_settings(hgserve) |
|
80 | return self.__load_web_settings(hgserve) | |
81 |
|
81 | |||
82 | def __get_environ_user(self, environ): |
|
82 | def __get_environ_user(self, environ): | |
83 | return environ.get('REMOTE_USER') |
|
83 | return environ.get('REMOTE_USER') | |
84 |
|
84 | |||
85 | def __get_action(self, environ): |
|
85 | def __get_action(self, environ): | |
86 | """ |
|
86 | """ | |
87 | Maps mercurial request commands into a pull or push command. |
|
87 | Maps mercurial request commands into a pull or push command. | |
88 | @param environ: |
|
88 | @param environ: | |
89 | """ |
|
89 | """ | |
90 | mapping = { |
|
90 | mapping = { | |
91 | 'changegroup': 'pull', |
|
91 | 'changegroup': 'pull', | |
92 | 'changegroupsubset': 'pull', |
|
92 | 'changegroupsubset': 'pull', | |
93 | 'unbundle': 'push', |
|
93 | 'unbundle': 'push', | |
94 | 'stream_out': 'pull', |
|
94 | 'stream_out': 'pull', | |
95 | } |
|
95 | } | |
96 | for qry in environ['QUERY_STRING'].split('&'): |
|
96 | for qry in environ['QUERY_STRING'].split('&'): | |
97 | if qry.startswith('cmd'): |
|
97 | if qry.startswith('cmd'): | |
98 | cmd = qry.split('=')[-1] |
|
98 | cmd = qry.split('=')[-1] | |
99 | if mapping.has_key(cmd): |
|
99 | if mapping.has_key(cmd): | |
100 | return mapping[cmd] |
|
100 | return mapping[cmd] | |
101 |
|
101 | |||
102 | def __log_user_action(self, username, action, repo): |
|
102 | def __log_user_action(self, username, action, repo): | |
103 | sa = meta.Session |
|
103 | sa = meta.Session | |
104 | try: |
|
104 | try: | |
105 | user = sa.query(User).filter(User.username == username).one() |
|
105 | user = sa.query(User).filter(User.username == username).one() | |
106 | user_log = UserLog() |
|
106 | user_log = UserLog() | |
107 | user_log.user_id = user.user_id |
|
107 | user_log.user_id = user.user_id | |
108 | user_log.action = action |
|
108 | user_log.action = action | |
109 | user_log.repository = repo.replace('/', '') |
|
109 | user_log.repository = repo.replace('/', '') | |
110 | user_log.action_date = datetime.now() |
|
110 | user_log.action_date = datetime.now() | |
111 | sa.add(user_log) |
|
111 | sa.add(user_log) | |
112 | sa.commit() |
|
112 | sa.commit() | |
113 | log.info('Adding user %s, action %s on %s', |
|
113 | log.info('Adding user %s, action %s on %s', | |
114 | username, action, repo) |
|
114 | username, action, repo) | |
115 | except Exception as e: |
|
115 | except Exception as e: | |
116 | sa.rollback() |
|
116 | sa.rollback() | |
117 | log.error('could not log user action:%s', str(e)) |
|
117 | log.error('could not log user action:%s', str(e)) | |
118 |
|
118 | |||
119 | def __invalidate_cache(self, repo_name): |
|
119 | def __invalidate_cache(self, repo_name): | |
120 | """we know that some change was made to repositories and we should |
|
120 | """we know that some change was made to repositories and we should | |
121 | invalidate the cache to see the changes right away but only for |
|
121 | invalidate the cache to see the changes right away but only for | |
122 | push requests""" |
|
122 | push requests""" | |
123 | invalidate_cache('cached_repo_list') |
|
123 | invalidate_cache('cached_repo_list') | |
124 | invalidate_cache('full_changelog', repo_name) |
|
124 | invalidate_cache('full_changelog', repo_name) | |
125 |
|
125 | |||
126 |
|
126 | |||
127 | def __load_web_settings(self, hgserve): |
|
127 | def __load_web_settings(self, hgserve): | |
128 | repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False) |
|
128 | repoui = make_ui(os.path.join(self.repo_path, '.hg', 'hgrc'), False) | |
129 | #set the global ui for hgserve |
|
129 | #set the global ui for hgserve | |
130 | hgserve.repo.ui = self.baseui |
|
130 | hgserve.repo.ui = self.baseui | |
131 |
|
131 | |||
132 | if repoui: |
|
132 | if repoui: | |
133 | #set the repository based config |
|
133 | #set the repository based config | |
134 | hgserve.repo.ui = repoui |
|
134 | hgserve.repo.ui = repoui | |
135 |
|
135 | |||
136 | return hgserve |
|
136 | return hgserve |
@@ -1,127 +1,130 b'' | |||||
1 | import os |
|
1 | import os | |
2 | import logging |
|
2 | import logging | |
3 | from mercurial import ui, config, hg |
|
3 | from mercurial import ui, config, hg | |
4 | from mercurial.error import RepoError |
|
4 | from mercurial.error import RepoError | |
5 | log = logging.getLogger(__name__) |
|
5 | log = logging.getLogger(__name__) | |
6 |
|
6 | |||
7 |
|
7 | |||
8 | def get_repo_slug(request): |
|
8 | def get_repo_slug(request): | |
9 | path_info = request.environ.get('PATH_INFO') |
|
9 | path_info = request.environ.get('PATH_INFO') | |
10 | uri_lst = path_info.split('/') |
|
10 | uri_lst = path_info.split('/') | |
11 | repo_name = uri_lst[1] |
|
11 | repo_name = uri_lst[1] | |
12 | return repo_name |
|
12 | return repo_name | |
13 |
|
13 | |||
14 | def is_mercurial(environ): |
|
14 | def is_mercurial(environ): | |
15 | """ |
|
15 | """ | |
16 | Returns True if request's target is mercurial server - header |
|
16 | Returns True if request's target is mercurial server - header | |
17 | ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``. |
|
17 | ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``. | |
18 | """ |
|
18 | """ | |
19 | http_accept = environ.get('HTTP_ACCEPT') |
|
19 | http_accept = environ.get('HTTP_ACCEPT') | |
20 | if http_accept and http_accept.startswith('application/mercurial'): |
|
20 | if http_accept and http_accept.startswith('application/mercurial'): | |
21 | return True |
|
21 | return True | |
22 | return False |
|
22 | return False | |
23 |
|
23 | |||
24 | def check_repo_dir(paths): |
|
24 | def check_repo_dir(paths): | |
25 | repos_path = paths[0][1].split('/') |
|
25 | repos_path = paths[0][1].split('/') | |
26 | if repos_path[-1] in ['*', '**']: |
|
26 | if repos_path[-1] in ['*', '**']: | |
27 | repos_path = repos_path[:-1] |
|
27 | repos_path = repos_path[:-1] | |
28 | if repos_path[0] != '/': |
|
28 | if repos_path[0] != '/': | |
29 | repos_path[0] = '/' |
|
29 | repos_path[0] = '/' | |
30 | if not os.path.isdir(os.path.join(*repos_path)): |
|
30 | if not os.path.isdir(os.path.join(*repos_path)): | |
31 | raise Exception('Not a valid repository in %s' % paths[0][1]) |
|
31 | raise Exception('Not a valid repository in %s' % paths[0][1]) | |
32 |
|
32 | |||
33 | def check_repo(repo_name, base_path): |
|
33 | def check_repo(repo_name, base_path): | |
34 |
|
34 | |||
35 | repo_path = os.path.join(base_path, repo_name) |
|
35 | repo_path = os.path.join(base_path, repo_name) | |
36 |
|
36 | |||
37 | try: |
|
37 | try: | |
38 | r = hg.repository(ui.ui(), repo_path) |
|
38 | r = hg.repository(ui.ui(), repo_path) | |
39 | hg.verify(r) |
|
39 | hg.verify(r) | |
40 | #here we hnow that repo exists it was verified |
|
40 | #here we hnow that repo exists it was verified | |
41 | log.info('%s repo is already created', repo_name) |
|
41 | log.info('%s repo is already created', repo_name) | |
42 | return False |
|
42 | return False | |
43 | #raise Exception('Repo exists') |
|
43 | #raise Exception('Repo exists') | |
44 | except RepoError: |
|
44 | except RepoError: | |
45 | log.info('%s repo is free for creation', repo_name) |
|
45 | log.info('%s repo is free for creation', repo_name) | |
46 | #it means that there is no valid repo there... |
|
46 | #it means that there is no valid repo there... | |
47 | return True |
|
47 | return True | |
48 |
|
48 | |||
49 |
def make_ui(path= |
|
49 | def make_ui(path=None, checkpaths=True): | |
50 | """ |
|
50 | """ | |
51 | A funcion that will read python rc files and make an ui from read options |
|
51 | A funcion that will read python rc files and make an ui from read options | |
52 |
|
52 | |||
53 | @param path: path to mercurial config file |
|
53 | @param path: path to mercurial config file | |
54 | """ |
|
54 | """ | |
|
55 | if not path: | |||
|
56 | log.error('repos config path is empty !') | |||
|
57 | ||||
55 | if not os.path.isfile(path): |
|
58 | if not os.path.isfile(path): | |
56 | log.warning('Unable to read config file %s' % path) |
|
59 | log.warning('Unable to read config file %s' % path) | |
57 | return False |
|
60 | return False | |
58 | #propagated from mercurial documentation |
|
61 | #propagated from mercurial documentation | |
59 | sections = [ |
|
62 | sections = [ | |
60 | 'alias', |
|
63 | 'alias', | |
61 | 'auth', |
|
64 | 'auth', | |
62 | 'decode/encode', |
|
65 | 'decode/encode', | |
63 | 'defaults', |
|
66 | 'defaults', | |
64 | 'diff', |
|
67 | 'diff', | |
65 | 'email', |
|
68 | 'email', | |
66 | 'extensions', |
|
69 | 'extensions', | |
67 | 'format', |
|
70 | 'format', | |
68 | 'merge-patterns', |
|
71 | 'merge-patterns', | |
69 | 'merge-tools', |
|
72 | 'merge-tools', | |
70 | 'hooks', |
|
73 | 'hooks', | |
71 | 'http_proxy', |
|
74 | 'http_proxy', | |
72 | 'smtp', |
|
75 | 'smtp', | |
73 | 'patch', |
|
76 | 'patch', | |
74 | 'paths', |
|
77 | 'paths', | |
75 | 'profiling', |
|
78 | 'profiling', | |
76 | 'server', |
|
79 | 'server', | |
77 | 'trusted', |
|
80 | 'trusted', | |
78 | 'ui', |
|
81 | 'ui', | |
79 | 'web', |
|
82 | 'web', | |
80 | ] |
|
83 | ] | |
81 |
|
84 | |||
82 | baseui = ui.ui() |
|
85 | baseui = ui.ui() | |
83 | cfg = config.config() |
|
86 | cfg = config.config() | |
84 | cfg.read(path) |
|
87 | cfg.read(path) | |
85 | if checkpaths:check_repo_dir(cfg.items('paths')) |
|
88 | if checkpaths:check_repo_dir(cfg.items('paths')) | |
86 |
|
89 | |||
87 | for section in sections: |
|
90 | for section in sections: | |
88 | for k, v in cfg.items(section): |
|
91 | for k, v in cfg.items(section): | |
89 | baseui.setconfig(section, k, v) |
|
92 | baseui.setconfig(section, k, v) | |
90 |
|
93 | |||
91 | return baseui |
|
94 | return baseui | |
92 |
|
95 | |||
93 | def invalidate_cache(name, *args): |
|
96 | def invalidate_cache(name, *args): | |
94 | """Invalidates given name cache""" |
|
97 | """Invalidates given name cache""" | |
95 |
|
98 | |||
96 | from beaker.cache import region_invalidate |
|
99 | from beaker.cache import region_invalidate | |
97 | log.info('INVALIDATING CACHE FOR %s', name) |
|
100 | log.info('INVALIDATING CACHE FOR %s', name) | |
98 |
|
101 | |||
99 | """propagate our arguments to make sure invalidation works. First |
|
102 | """propagate our arguments to make sure invalidation works. First | |
100 | argument has to be the name of cached func name give to cache decorator |
|
103 | argument has to be the name of cached func name give to cache decorator | |
101 | without that the invalidation would not work""" |
|
104 | without that the invalidation would not work""" | |
102 | tmp = [name] |
|
105 | tmp = [name] | |
103 | tmp.extend(args) |
|
106 | tmp.extend(args) | |
104 | args = tuple(tmp) |
|
107 | args = tuple(tmp) | |
105 |
|
108 | |||
106 | if name == 'cached_repo_list': |
|
109 | if name == 'cached_repo_list': | |
107 | from pylons_app.lib.base import _get_repos_cached |
|
110 | from pylons_app.lib.base import _get_repos_cached | |
108 | region_invalidate(_get_repos_cached, None, *args) |
|
111 | region_invalidate(_get_repos_cached, None, *args) | |
109 |
|
112 | |||
110 | if name == 'full_changelog': |
|
113 | if name == 'full_changelog': | |
111 | from pylons_app.lib.base import _full_changelog_cached |
|
114 | from pylons_app.lib.base import _full_changelog_cached | |
112 | region_invalidate(_full_changelog_cached, None, *args) |
|
115 | region_invalidate(_full_changelog_cached, None, *args) | |
113 |
|
116 | |||
114 | from vcs.backends.base import BaseChangeset |
|
117 | from vcs.backends.base import BaseChangeset | |
115 | from vcs.utils.lazy import LazyProperty |
|
118 | from vcs.utils.lazy import LazyProperty | |
116 | class EmptyChangeset(BaseChangeset): |
|
119 | class EmptyChangeset(BaseChangeset): | |
117 |
|
120 | |||
118 | revision = -1 |
|
121 | revision = -1 | |
119 |
|
122 | |||
120 | @LazyProperty |
|
123 | @LazyProperty | |
121 | def raw_id(self): |
|
124 | def raw_id(self): | |
122 | """ |
|
125 | """ | |
123 | Returns raw string identifing this changeset, useful for web |
|
126 | Returns raw string identifing this changeset, useful for web | |
124 | representation. |
|
127 | representation. | |
125 | """ |
|
128 | """ | |
126 | return '0' * 12 |
|
129 | return '0' * 12 | |
127 |
|
130 |
1 | NO CONTENT: file renamed from hgwebdir.config to repositories.config |
|
NO CONTENT: file renamed from hgwebdir.config to repositories.config |
General Comments 0
You need to be logged in to leave comments.
Login now