Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.buildout
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Thomas Leymonerie
slapos.buildout
Commits
8a087b51
Commit
8a087b51
authored
May 12, 2012
by
Jim Fulton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
normalize the way default options are handled and documented
Cherry-picked from trunk. Thanks Gary.
parent
8a3f1e9f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
259 additions
and
161 deletions
+259
-161
src/zc/buildout/buildout.py
src/zc/buildout/buildout.py
+45
-31
src/zc/buildout/buildout.txt
src/zc/buildout/buildout.txt
+202
-123
src/zc/buildout/tests.py
src/zc/buildout/tests.py
+5
-0
zc.recipe.egg_/src/zc/recipe/egg/egg.py
zc.recipe.egg_/src/zc/recipe/egg/egg.py
+7
-7
No files found.
src/zc/buildout/buildout.py
View file @
8a087b51
...
...
@@ -108,13 +108,24 @@ def _unannotate(data):
return
data
_buildout_default_options
=
_annotate_section
({
'
eggs-directory'
:
'eggs
'
,
'
develop-eggs-directory'
:
'develop-eggs
'
,
'
allow-hosts'
:
'*
'
,
'
allow-picked-versions'
:
'true
'
,
'bin-directory'
:
'bin'
,
'parts-directory'
:
'parts'
,
'develop-eggs-directory'
:
'develop-eggs'
,
'eggs-directory'
:
'eggs'
,
'executable'
:
sys
.
executable
,
'find-links'
:
''
,
'install-from-cache'
:
'false'
,
'installed'
:
'.installed.cfg'
,
'log-level'
:
'INFO'
,
'log-format'
:
''
,
'log-level'
:
'INFO'
,
'newest'
:
'true'
,
'offline'
:
'false'
,
'parts-directory'
:
'parts'
,
'prefer-final'
:
'false'
,
'python'
:
'buildout'
,
'unzip'
:
'false'
,
'use-dependency-links'
:
'true'
,
},
'DEFAULT_VALUE'
)
# _buildout_version and _buildout_1_4_default_versions are part of a
...
...
@@ -201,7 +212,7 @@ class Buildout(UserDict.DictMixin):
# provide some defaults before options are parsed
# because while parsing options those attributes might be
# used already (Gottfried Ganssauge)
buildout_section
=
data
.
get
(
'buildout'
)
buildout_section
=
data
[
'buildout'
]
# Try to make sure we have absolute paths for standard
# directories. We do this before doing substitutions, in case
...
...
@@ -214,22 +225,28 @@ class Buildout(UserDict.DictMixin):
d
=
self
.
_buildout_path
(
buildout_section
[
name
+
'-directory'
])
buildout_section
[
name
+
'-directory'
]
=
d
links
=
buildout_section
and
buildout_section
.
get
(
'find-links'
,
''
)
# Attributes on this buildout object shouldn't be used by
# recipes in their __init__. It can cause bugs, because the
# recipes will be instantiated below (``options = self['buildout']``)
# before this has completed initializing. These attributes are
# left behind for legacy support but recipe authors should
# beware of using them. A better practice is for a recipe to
# use the buildout['buildout'] options.
links
=
buildout_section
[
'find-links'
]
self
.
_links
=
links
and
links
.
split
()
or
()
allow_hosts
=
buildout_section
and
buildout_section
.
get
(
'allow-hosts'
,
'*'
).
split
(
'
\
n
'
)
allow_hosts
=
buildout_section
[
'allow-hosts'
].
split
(
'
\
n
'
)
self
.
_allow_hosts
=
tuple
([
host
.
strip
()
for
host
in
allow_hosts
if
host
.
strip
()
!=
''
])
self
.
_logger
=
logging
.
getLogger
(
'zc.buildout'
)
self
.
offline
=
False
self
.
newest
=
True
self
.
offline
=
(
buildout_section
[
'offline'
]
==
'true'
)
self
.
newest
=
(
buildout_section
[
'newest'
]
==
'true'
)
##################################################################
## WARNING!!!
## ALL ATTRIBUTES MUST HAVE REASONABLE DEFAULTS AT THIS POINT
## OTHERWISE ATTRIBUTEERRORS MIGHT HAPPEN ANY TIME
## OTHERWISE ATTRIBUTEERRORS MIGHT HAPPEN ANY TIME FROM RECIPES.
## RECIPES SHOULD GENERALLY USE buildout['buildout'] OPTIONS, NOT
## BUILDOUT ATTRIBUTES.
##################################################################
# initialize some attrs and buildout directories.
options
=
self
[
'buildout'
]
...
...
@@ -238,7 +255,7 @@ class Buildout(UserDict.DictMixin):
links
=
options
.
get
(
'find-links'
,
''
)
self
.
_links
=
links
and
links
.
split
()
or
()
allow_hosts
=
options
.
get
(
'allow-hosts'
,
'*'
)
.
split
(
'
\
n
'
)
allow_hosts
=
options
[
'allow-hosts'
]
.
split
(
'
\
n
'
)
self
.
_allow_hosts
=
tuple
([
host
.
strip
()
for
host
in
allow_hosts
if
host
.
strip
()
!=
''
])
...
...
@@ -256,20 +273,18 @@ class Buildout(UserDict.DictMixin):
self
.
_setup_logging
()
offline
=
options
.
get
(
'offline'
,
'false'
)
offline
=
options
[
'offline'
]
if
offline
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for offline option: %s'
,
offline
)
options
[
'offline'
]
=
offline
self
.
offline
=
offline
==
'true'
self
.
offline
=
(
offline
==
'true'
)
if
self
.
offline
:
newest
=
options
[
'newest'
]
=
'false'
else
:
newest
=
options
.
get
(
'newest'
,
'true'
)
newest
=
options
[
'newest'
]
if
newest
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for newest option: %s'
,
newest
)
options
[
'newest'
]
=
newest
self
.
newest
=
newest
==
'true'
self
.
newest
=
(
newest
==
'true'
)
# This is a hacked version of zc.buildout for 1.4.4.
# This means that buildout uses the defaults set up above. The point
...
...
@@ -282,25 +297,25 @@ class Buildout(UserDict.DictMixin):
versions
.
update
(
dict
(
self
[
versions_section
]))
zc
.
buildout
.
easy_install
.
default_versions
(
versions
)
prefer_final
=
options
.
get
(
'prefer-final'
,
'false'
)
prefer_final
=
options
[
'prefer-final'
]
if
prefer_final
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for prefer-final option: %s'
,
prefer_final
)
zc
.
buildout
.
easy_install
.
prefer_final
(
prefer_final
==
'true'
)
use_dependency_links
=
options
.
get
(
'use-dependency-links'
,
'true'
)
use_dependency_links
=
options
[
'use-dependency-links'
]
if
use_dependency_links
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for use-dependency-links option: %s'
,
use_dependency_links
)
zc
.
buildout
.
easy_install
.
use_dependency_links
(
use_dependency_links
==
'true'
)
allow_picked_versions
=
options
.
get
(
'allow-picked-versions'
,
'true'
)
allow_picked_versions
=
options
[
'allow-picked-versions'
]
if
allow_picked_versions
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for allow-picked-versions option: %s'
,
allow_picked_versions
)
zc
.
buildout
.
easy_install
.
allow_picked_versions
(
allow_picked_versions
==
'true'
)
allow_picked_versions
==
'true'
)
download_cache
=
options
.
get
(
'download-cache'
)
if
download_cache
:
...
...
@@ -317,13 +332,12 @@ class Buildout(UserDict.DictMixin):
zc
.
buildout
.
easy_install
.
download_cache
(
download_cache
)
install_from_cache
=
options
.
get
(
'install-from-cache'
)
if
install_from_cache
:
if
install_from_cache
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for install-from-cache option: %s'
,
install_from_cache
)
if
install_from_cache
==
'true'
:
zc
.
buildout
.
easy_install
.
install_from_cache
(
True
)
install_from_cache
=
options
[
'install-from-cache'
]
if
install_from_cache
not
in
(
'true'
,
'false'
):
self
.
_error
(
'Invalid value for install-from-cache option: %s'
,
install_from_cache
)
zc
.
buildout
.
easy_install
.
install_from_cache
(
install_from_cache
==
'true'
)
# "Use" each of the defaults so they aren't reported as unused options.
for
name
in
_buildout_default_options
:
...
...
src/zc/buildout/buildout.txt
View file @
8a087b51
...
...
@@ -504,7 +504,7 @@ Let's fix the recipe:
>>> write(sample_buildout, 'recipes', 'mkdir.py',
... """
... import logging, os, zc.buildout
... import logging, os, zc.buildout
, sys
...
... class Mkdir:
...
...
...
@@ -533,13 +533,15 @@ Let's fix the recipe:
... 'Creating directory %s', os.path.basename(path))
... os.mkdir(path)
... created.append(path)
... except:
... except
Exception
:
... for d in created:
... os.rmdir(d)
... assert not os.path.exists(d)
... logging.getLogger(self.name).info(
... 'Removed %s due to error',
... os.path.basename(d))
... sys.stderr.flush()
... sys.stdout.flush()
... raise
...
... return paths
...
...
@@ -581,7 +583,7 @@ When we rerun the buildout:
.. Wait for the file to really disappear. My linux is weird.
>>> wait_until("foo goes away", lambda : not os.path.exists('foo'),
... timeout=
1
00)
... timeout=
2
00)
we get the same error, but we don't get the directory left behind:
...
...
@@ -729,6 +731,10 @@ COMMAND_LINE_VALUE).
==================
<BLANKLINE>
[buildout]
allow-hosts= *
DEFAULT_VALUE
allow-picked-versions= true
DEFAULT_VALUE
bin-directory= bin
DEFAULT_VALUE
develop= recipes
...
...
@@ -739,16 +745,34 @@ COMMAND_LINE_VALUE).
COMPUTED_VALUE
eggs-directory= eggs
DEFAULT_VALUE
executable= ...
DEFAULT_VALUE
find-links=
DEFAULT_VALUE
install-from-cache= false
DEFAULT_VALUE
installed= .installed.cfg
DEFAULT_VALUE
log-format=
DEFAULT_VALUE
log-level= INFO
DEFAULT_VALUE
newest= true
DEFAULT_VALUE
offline= false
DEFAULT_VALUE
parts= data-dir
/sample-buildout/buildout.cfg
parts-directory= parts
DEFAULT_VALUE
prefer-final= false
DEFAULT_VALUE
python= buildout
DEFAULT_VALUE
unzip= false
DEFAULT_VALUE
use-dependency-links= true
DEFAULT_VALUE
<BLANKLINE>
[data-dir]
path= foo bins
...
...
@@ -2201,10 +2225,15 @@ database is shown.
<BLANKLINE>
Configuration data:
[buildout]
allow-hosts = *
allow-picked-versions = true
bin-directory = /sample-buildout/bin
develop-eggs-directory = /sample-buildout/develop-eggs
directory = /sample-buildout
eggs-directory = /sample-buildout/eggs
executable = python
find-links =
install-from-cache = false
installed = /sample-buildout/.installed.cfg
log-format =
log-level = INFO
...
...
@@ -2212,6 +2241,10 @@ database is shown.
offline = false
parts =
parts-directory = /sample-buildout/parts
prefer-final = false
python = buildout
unzip = false
use-dependency-links = true
verbosity = 20
<BLANKLINE>
...
...
@@ -2219,6 +2252,37 @@ All of these options can be overridden by configuration files or by
command-line assignments. We've discussed most of these options
already, but let's review them and touch on some we haven't discussed:
allow-hosts
On some environments the links visited by `zc.buildout` can be forbidden by
paranoid firewalls. These URLs might be in the chain of links visited by
`zc.buildout` as defined by buildout's `find-links` option, or as defined
by various eggs in their `url`, `download_url`, `dependency_links` metadata.
The fact that package_index works like a spider and might visit links and
go to other locations makes this even harder.
The `allow-hosts` option provides a way to prevent this, and
works exactly like the one provided in `easy_install`.
You can provide a list of allowed host, together with wildcards::
[buildout]
...
allow-hosts =
*.python.org
example.com
All URLs that does not match these hosts will not be visited.
allow-picked-versions
By default, the buildout will choose the best match for a given requirement
if the requirement is not specified precisely (for instance, using the
"versions" option. This behavior corresponds to the
"allow-picked-versions" being set to its default value, "true". If
"allow-picked-versions" is "false," instead of picking the best match,
buildout will raise an error. This helps enforce repeatability.
bin-directory
The directory path where scripts are written. This can be a
relative path, which is interpreted relative to the directory
...
...
@@ -2239,6 +2303,51 @@ eggs-directory
*never* be modified. This can be a relative path, which is
interpreted relative to the directory option.
executable
The Python executable used to run the buildout. See the python
option below.
find-links
You can specify more locations to search for distributions using the
`find-links` option. All locations specified will be searched for
distributions along with the package index as described before.
Locations can be urls::
[buildout]
...
find-links = http://download.zope.org/distribution/
They can also be directories on disk::
[buildout]
...
find-links = /some/path
Finally, they can also be direct paths to distributions::
[buildout]
...
find-links = /some/path/someegg-1.0.0-py2.3.egg
Any number of locations can be specified in the `find-links` option::
[buildout]
...
find-links =
http://download.zope.org/distribution/
/some/otherpath
/some/path/someegg-1.0.0-py2.3.egg
install-from-cache
A download cache can be used as the basis of application source releases.
In an application source release, we want to distribute an application that
can be built without making any network accesses. In this case, we
distribute a buildout with download cache and tell the buildout to install
from the download cache only, without making network accesses. The
buildout install-from-cache option can be used to signal that packages
should be installed only from the download cache.
installed
The file path where information about the results of the previous
buildout run is written. This can be a relative path, which is
...
...
@@ -2252,12 +2361,101 @@ log-format
log-level
The log level before verbosity adjustment
newest
By default buildout and recipes will try to find the newest versions of
distributions needed to satisfy requirements. This can be very time
consuming, especially when incrementally working on setting up a buildout
or working on a recipe. The buildout "newest" option can be used to to
suppress this. If the "newest" option is set to false, then new
distributions won't be sought if an installed distribution meets
requirements. The "newest" option can also be set to false using the -N
command-line option. See also the "offline" option.
offline
The "offline" option goes a bit further than the "newest" option. If the
buildout "offline" option is given a value of "true", the buildout and
recipes that are aware of the option will avoid doing network access. This
is handy when running the buildout when not connected to the internet. It
also makes buildouts run much faster. This option is typically set using
the buildout -o option.
parts
A white space separated list of parts to be installed.
parts-directory
A working directory that parts can used to store data.
prefer-final
Currently, when searching for new releases, the newest available
release is used. This isn't usually ideal, as you may get a
development release or alpha releases not ready to be widely used.
You can request that final releases be preferred using the prefer
final option in the buildout section::
[buildout]
...
prefer-final = true
When the prefer-final option is set to true, then when searching for
new releases, final releases are preferred. If there are final
releases that satisfy distribution requirements, then those releases
are used even if newer non-final releases are available. The buildout
prefer-final option can be used to override this behavior.
In buildout version 2, final releases will be preferred by default.
You will then need to use a false value for prefer-final to get the
newest releases.
python
The name of a section containing information about the default
Python interpreter. Recipes that need a installation
typically have options to tell them which Python installation to
use. By convention, if a section-specific option isn't used, the
option is looked for in the buildout section. The option must
point to a section with an executable option giving the path to a
Python executable. By default, the buildout section defines the
default Python as the Python used to run the buildout.
unzip
By default, zc.buildout doesn't unzip zip-safe eggs ("unzip = false").
This follows the policy followed by setuptools itself. Experience shows
this policy to to be inconvenient. Zipped eggs make debugging more
difficult and often import more slowly. You can include an unzip option in
the buildout section to change the default unzipping policy ("unzip =
true").
use-dependency-links
By default buildout will obey the setuptools dependency_links metadata
when it looks for dependencies. This behavior can be controlled with
the use-dependency-links buildout option::
[buildout]
...
use-dependency-links = false
The option defaults to true. If you set it to false, then dependency
links are only looked for in the locations specified by find-links.
unzip
By default, zc.buildout doesn't unzip zip-safe eggs ("unzip = false").
This follows the policy followed by setuptools itself. Experience shows
this policy to to be inconvenient. Zipped eggs make debugging more
difficult and often import more slowly. You can include an unzip option in
the buildout section to change the default unzipping policy ("unzip =
true").
use-dependency-links
By default buildout will obey the setuptools dependency_links metadata
when it looks for dependencies. This behavior can be controlled with
the use-dependency-links buildout option::
[buildout]
...
use-dependency-links = false
The option defaults to true. If you set it to false, then dependency
links are only looked for in the locations specified by find-links.
verbosity
A log-level adjustment. Typically, this is set via the -q and -v
command-line options.
...
...
@@ -2336,48 +2534,6 @@ if there isn't a configuration file:
Generated script '/sample-bootstrapped2/bin/buildout'.
Newest and Offline Modes
------------------------
By default buildout and recipes will try to find the newest versions
of distributions needed to satisfy requirements. This can be very
time consuming, especially when incrementally working on setting up a
buildout or working on a recipe. The buildout newest option can be
used to to suppress this. If the newest option is set to false, then
new distributions won't be sought if an installed distribution meets
requirements. The newest option can be set to false using the -N
command-line option.
The offline option goes a bit further. If the buildout offline option
is given a value of "true", the buildout and recipes that are aware of
the option will avoid doing network access. This is handy when
running the buildout when not connected to the internet. It also
makes buildouts run much faster. This option is typically set using
the buildout -o option.
Preferring Final Releases
-------------------------
Currently, when searching for new releases, the newest available
release is used. This isn't usually ideal, as you may get a
development release or alpha releases not ready to be widely used.
You can request that final releases be preferred using the prefer
final option in the buildout section::
[buildout]
...
prefer-final = true
When the prefer-final option is set to true, then when searching for
new releases, final releases are preferred. If there are final
releases that satisfy distribution requirements, then those releases
are used even if newer non-final releases are available. The buildout
prefer-final option can be used to override this behavior.
In buildout version 2, final releases will be preferred by default.
You will then need to use a false value for prefer-final to get the
newest releases.
Finding distributions
---------------------
...
...
@@ -2396,49 +2552,7 @@ distributions. The latest version of the distribution that meets the
requirements of the buildout will always be used.
You can also specify more locations to search for distributions using
the `find-links` option. All locations specified will be searched for
distributions along with the package index as described before.
Locations can be urls::
[buildout]
...
find-links = http://download.zope.org/distribution/
They can also be directories on disk::
[buildout]
...
find-links = /some/path
Finally, they can also be direct paths to distributions::
[buildout]
...
find-links = /some/path/someegg-1.0.0-py2.3.egg
Any number of locations can be specified in the `find-links` option::
[buildout]
...
find-links =
http://download.zope.org/distribution/
/some/otherpath
/some/path/someegg-1.0.0-py2.3.egg
Dependency links
----------------
By default buildout will obey the setuptools dependency_links metadata
when it looks for dependencies. This behavior can be controlled with
the use-dependency-links buildout option::
[buildout]
...
use-dependency-links = false
The option defaults to true. If you set it to false, then dependency
links are only looked for in the locations specified by find-links.
the `find-links` option. See its description above.
Controlling the installation database
-------------------------------------
...
...
@@ -2599,38 +2713,3 @@ We see that our extension is loaded and executed:
ext ['buildout']
Develop: '/sample-bootstrapped/demo'
unload ['buildout']
Allow hosts
-----------
On some environments the links visited by `zc.buildout` can be forbidden
by paranoiac firewalls. These URL might be on the chain of links
visited by `zc.buildout` wheter they are defined in the `find-links` option,
wheter they are defined by various eggs in their `url`, `download_url`,
`dependency_links` metadata.
It is even harder to track that package_index works like a spider and
might visit links and go to other location.
The `allow-hosts` option provides a way to prevent this, and
works exactly like the one provided in `easy_install`.
You can provide a list of allowed host, together with wildcards::
[buildout]
...
allow-hosts =
*.python.org
example.com
All urls that does not match these hosts will not be visited.
.. [#future_recipe_methods] In the future, additional methods may be
added. Older recipes with fewer methods will still be
supported.
.. [#packaging_info] If we wanted to create a distribution from this
package, we would need specify much more information. See the
`setuptools documentation
<http://peak.telecommunity.com/DevCenter/setuptools>`_.
src/zc/buildout/tests.py
View file @
8a087b51
...
...
@@ -2851,6 +2851,8 @@ def test_suite():
r'
when
that
file
already
exists
:
'),
'
[
Errno
17
]
File
exists
:
'
),
(re.compile('
executable
=
%
s
' % re.escape(sys.executable)),
'
executable
=
python
'),
])
),
doctest.DocFileSuite(
...
...
@@ -2947,6 +2949,9 @@ def test_suite():
'-q develop -mxN -d /sample-buildout/develop-eggs'
),
(re.compile(r'^[*]...'), '...'),
# for bug_92891_bootstrap_crashes_with_egg_recipe_in_buildout_section
(re.compile(r"
Unused
options
for
buildout
:
'eggs'
'scripts'
\
.
"),
"
Unused
options
for
buildout
:
'scripts'
'eggs'
.
"),
]),
),
zc.buildout.rmtree.test_suite(),
...
...
zc.recipe.egg_/src/zc/recipe/egg/egg.py
View file @
8a087b51
...
...
@@ -27,8 +27,8 @@ class Eggs(object):
self
.
buildout
=
buildout
self
.
name
=
name
self
.
options
=
options
links
=
options
.
get
(
'find-links'
,
buildout
[
'buildout'
].
get
(
'find-links'
)
)
b_options
=
buildout
[
'buildout'
]
links
=
options
.
get
(
'find-links'
,
b_options
[
'find-links'
]
)
if
links
:
links
=
links
.
split
()
options
[
'find-links'
]
=
'
\
n
'
.
join
(
links
)
...
...
@@ -36,20 +36,19 @@ class Eggs(object):
links
=
()
self
.
links
=
links
index
=
options
.
get
(
'index'
,
b
uildout
[
'buildout'
]
.
get
(
'index'
))
index
=
options
.
get
(
'index'
,
b
_options
.
get
(
'index'
))
if
index
is
not
None
:
options
[
'index'
]
=
index
self
.
index
=
index
allow_hosts
=
b
uildout
[
'buildout'
].
get
(
'allow-hosts'
,
'*'
)
allow_hosts
=
b
_options
[
'allow-hosts'
]
allow_hosts
=
tuple
([
host
.
strip
()
for
host
in
allow_hosts
.
split
(
'
\
n
'
)
if
host
.
strip
()
!=
''
])
self
.
allow_hosts
=
allow_hosts
options
[
'eggs-directory'
]
=
b
uildout
[
'buildout'
]
[
'eggs-directory'
]
options
[
'eggs-directory'
]
=
b
_options
[
'eggs-directory'
]
options
[
'_e'
]
=
options
[
'eggs-directory'
]
# backward compat.
options
[
'develop-eggs-directory'
]
=
buildout
[
'buildout'
][
'develop-eggs-directory'
]
options
[
'develop-eggs-directory'
]
=
b_options
[
'develop-eggs-directory'
]
options
[
'_d'
]
=
options
[
'develop-eggs-directory'
]
# backward compat.
def
working_set
(
self
,
extra
=
()):
...
...
@@ -58,6 +57,7 @@ class Eggs(object):
This is intended for reuse by similar recipes.
"""
options
=
self
.
options
b_options
=
self
.
buildout
[
'buildout'
]
# Backward compat. :(
options
[
'executable'
]
=
sys
.
executable
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment