Rev 63: Add pyftpdlib support, not all bzr tests passing. in file:///net/bigmamac/Volumes/home/vila/.bazaar/plugins/local_test_server/

Vincent Ladeuil v.ladeuil+lp at free.fr
Thu Feb 26 15:09:38 GMT 2009


At file:///net/bigmamac/Volumes/home/vila/.bazaar/plugins/local_test_server/

------------------------------------------------------------
revno: 63
revision-id: v.ladeuil+lp at free.fr-20090226150932-nfi7723hshm9f2x2
parent: v.ladeuil+lp at free.fr-20090225122349-pmbzis0scoqtf7bo
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: local_test_server
timestamp: Thu 2009-02-26 16:09:32 +0100
message:
  Add pyftpdlib support, not all bzr tests passing.
  
  * tests/test_utils.py:
  (full_scenarios): Add scenario for pyftpdlib.
  
  * test_server.py:
  (PyftpdlibFeature): New class.
  (Muddleftpd.tearDown): Oops, forgot to delete the symlink.
  (Pyftpdlib): Test server serving '/' for anonymous ftp.
  
  * server.py:
  (Server._start_by_spawning): Factored out from Vsftpd._start.
  (Vsftpd._start): Simplified.
  (Pyftpdlib): Spawn a pyftpdlib FTP server.
  
  * configs/pyftpdlib.conf: 
  Rough configuration options.
  
  * config.py:
  (Pyftpdlib): New class.
  
  * bin/pyftpdlib: 
  Wrapper to start a pyftpdlib FTP server.
-------------- next part --------------
=== added directory 'bin'
=== added file 'bin/pyftpdlib'
--- a/bin/pyftpdlib	1970-01-01 00:00:00 +0000
+++ b/bin/pyftpdlib	2009-02-26 15:09:32 +0000
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+import sys
+from pyftpdlib import ftpserver
+
+class AnonymousWithWriteAccessAuthorizer(ftpserver.DummyAuthorizer):
+
+    def _check_permissions(self, username, perm):
+        # Like base implementation but don't warn about write permissions
+        # assigned to anonynous, since that exactly our purpose.
+        for p in perm:
+            if p not in self.read_perms + self.write_perms:
+                raise ftpserver.AuthorizerError('No such permission "%s"' %p)
+
+
+def start_server(conf):
+    authorizer = AnonymousWithWriteAccessAuthorizer()
+    authorizer.add_user('anonymous', None, '/', perm='elradfmw')
+    ftpserver.FTPHandler.authorizer = authorizer
+    address = (conf['host'], conf['port'])
+    ftpd = ftpserver.FTPServer(address, ftpserver.FTPHandler)
+    log_file = open(conf['log_file'], 'w')
+    def do_log(msg):
+        log_file.write(msg + '\n')
+        log_file.flush()
+
+    ftpserver.log = ftpserver.logline = ftpserver.logerror = do_log
+    try:
+        ftpd.serve_forever()
+    finally:
+        log_file_close()
+
+def  main():
+    conf_path = sys.argv[1]
+    conf = {}
+    conf_file = open(conf_path)
+    try:
+        for l in conf_file:
+            l = l.rstrip('\n')
+            # Strip comments
+            comment_start = l.find('#')
+            if comment_start >= 0: l = l[:comment_start]
+            # Ignore empty line
+            if not l: continue
+            key, value = l.split(None, 1)
+            conf[key] = value
+    finally:
+        conf_file.close()
+    conf['port'] = int(conf['port'])
+    start_server(conf)
+
+
+main()

=== modified file 'config.py'
--- a/config.py	2009-02-25 12:23:49 +0000
+++ b/config.py	2009-02-26 15:09:32 +0000
@@ -191,5 +191,6 @@
     _required_dirs = Config._required_dirs + ('var/lock',)
 
 
-
-
+class Pyftpdlib(Config):
+
+    name = 'pyftpdlib'

=== added file 'configs/pyftpdlib.conf'
--- a/configs/pyftpdlib.conf	1970-01-01 00:00:00 +0000
+++ b/configs/pyftpdlib.conf	2009-02-26 15:09:32 +0000
@@ -0,0 +1,17 @@
+# pyftpdlib configuration
+
+# each line is key<space(s)>value
+
+server_name %(server_name)s
+base_dir %(base_dir)s
+host %(host)s
+port %(port)s
+pid_file %(pid_file)s
+log_file %(log_file)s
+
+user %(user)s
+
+etc_dir %(etc_dir)s
+var_run_dir %(var_run_dir)s
+var_log_dir %(var_log_dir)s
+data_dir %(data_dir)s

=== modified file 'server.py'
--- a/server.py	2009-02-24 21:15:01 +0000
+++ b/server.py	2009-02-26 15:09:32 +0000
@@ -18,6 +18,8 @@
 The classes described here provide an interface with the real servers.
 """
 
+import sys
+
 try:
     import kerberos
     has_kerberos = True
@@ -156,9 +158,9 @@
     def start(self):
         if self.is_running():
             raise LTSAlreadyRunningError(self)
+        self.config.ensure_required_dirs_exist()
         # Create the config to be used by the real server
         infile = open(self.config.config_path)
-        self.config.ensure_required_dirs_exist()
         outfile = open(self.output_config_path, 'wt')
         try:
             self.config.expand(infile, outfile)
@@ -388,6 +390,27 @@
                 self, extra='%s returned  non-zero exit status %d'
                 % (apparent_cmd_name, retcode))
 
+    def _start_by_spawning(self, cmd_args, apparent_cmd_name=None,
+                           create_pid_file=True):
+        """Start the server by spawning a command without waiting.
+
+        A failure to execute the command is fatal.
+        The pid file is created on request.
+        """
+        if apparent_cmd_name is None:
+            apparent_cmd_name = cmd_args[0]
+        proc = subprocess.Popen(cmd_args)
+        if proc.returncode is not None:
+            raise LTSCantStartError(
+                self, 'return code: %s, while spawing %s'
+                % (proc.returncode, apparent_cmd_name))
+        if create_pid_file:
+            f = open(self.get_config_value('pid_file'), 'w')
+            try:
+                f.write('%s' % proc.pid)
+            finally:
+                f.close()
+
 
 class Apache2(Server):
 
@@ -628,15 +651,8 @@
         # goes wrong during server launch... There is nothing in the log to get
         # confirmation that the start went right, the log file itself is not
         # created before the first connection :-/
-        proc = subprocess.Popen([self._server_command_name,
+        self._start_by_spawning([self._server_command_name,
                                  self.output_config_path])
-        if proc.returncode is not None:
-            raise LTSCantStartError(self, 'return code: %s' % proc.returncode)
-        f = open(self.get_config_value('pid_file'), 'w')
-        try:
-            f.write('%s' % proc.pid)
-        finally:
-            f.close()
 
     def _stop(self):
         if not self._wait_for_server_process_death():
@@ -741,6 +757,36 @@
             raise LTSCantStopError(self)
 
 
+class Pyftpdlib(Server):
+
+    def __init__(self, port, conf=None):
+        if conf is None:
+            conf = config.Pyftpdlib()
+        super(Pyftpdlib, self).__init__(port, conf)
+        self.output_config_path = self.config.abspath('etc/pyftpdlib.conf')
+        # Be sure to use the currently running python
+        self._server_command_name = sys.executable
+
+    def is_installed(self):
+        try:
+            import pyftpdlib.ftpserver
+            return True
+        except ImportError:
+            return False
+
+    def _start(self):
+        self._start_by_spawning([self._server_command_name,
+                                 config.get_lts_path('bin/pyftpdlib'),
+                                 self.output_config_path],
+                                apparent_cmd_name='pyftpdlib')
+
+    def _stop(self):
+        if not self._wait_for_server_process_death():
+            raise LTSCantStopError(self)
+        # We need to delete the pid file ourselves
+        osutils.delete_any(self.get_config_value('pid_file'))
+
+
 # For self tests we use a range of unassigned port numbers as described
 # in http://www.iana.org/assignments/port-numbers
 # We use the 29168-30000 range
@@ -787,6 +833,7 @@
 _servers['proftpd'] = Proftpd(25018)
 _servers['apache2-https'] = Apache2HTTPS(25019)
 _servers['muddleftpd'] = Muddleftpd(25020)
+_servers['pyftpdlib'] = Pyftpdlib(25021)
 
 
 def get_server(name):

=== modified file 'test_server.py'
--- a/test_server.py	2009-02-23 17:00:14 +0000
+++ b/test_server.py	2009-02-26 15:09:32 +0000
@@ -120,6 +120,11 @@
     _server_name = 'muddleftpd'
 
 
+class PyftpdlibFeature(LocalTestServerFeature):
+
+    _server_name = 'pyftpdlib'
+
+
 class LocalTestServer(transport.Server):
 
     # Must be set by daughter classes
@@ -345,6 +350,12 @@
         super(Muddleftpd, self).setUp(backing_transport_server)
         self._build_symlink_under_data_dir()
 
+    def tearDown(self):
+        """See bzrlib.transport.Server.tearDown."""
+        super(Muddleftpd, self).tearDown()
+        data_dir = self._server.get_config_value('data_dir')
+        osutils.delete_any(osutils.pathjoin(data_dir, self._symlink_name))
+
     def _build_base_url(self):
         user = 'anonymous'
         return '%s://%s@%s:%s/' % (self._url_protocol, user,
@@ -355,6 +366,20 @@
         return self._base_url + self._symlink_name
 
 
+class Pyftpdlib(LocalFTPTestServer):
+
+    _server_name = 'pyftpdlib'
+
+    def _build_base_url(self):
+        user = 'anonymous'
+        return '%s://%s@%s:%s' % (self._url_protocol, user,
+                                  self.host, self.port)
+
+    def get_url(self):
+        """See bzrlib.transport.Server.get_url."""
+        return self._base_url + self._test_working_dir
+
+
 # We have registered a transport for the purpose of adding new servers in the
 # test permutations. Registering a transport makes our module appears in the
 # list which is queried for a get_test_permutations function.
@@ -422,4 +447,7 @@
     if MuddleftpdFeature().available():
         permutations.append((FtpTransport, Muddleftpd))
 
+    if PyftpdlibFeature().available():
+        permutations.append((FtpTransport, Pyftpdlib))
+
     return permutations

=== modified file 'tests/test_utils.py'
--- a/tests/test_utils.py	2009-02-23 13:12:18 +0000
+++ b/tests/test_utils.py	2009-02-26 15:09:32 +0000
@@ -174,6 +174,13 @@
                 _server_feature_class=test_server.MuddleftpdFeature,
                 _test_server_class=test_server.Muddleftpd,
                 )),
+        ('pyftpdlib', dict(
+                _server_name='pyftpdlib',
+                _config_class=config.Pyftpdlib,
+                _server_class=server.Pyftpdlib,
+                _server_feature_class=test_server.PyftpdlibFeature,
+                _test_server_class=test_server.Pyftpdlib,
+                )),
         ]
     return scenarios
 



More information about the bazaar-commits mailing list