def handle(self, *args, **options):
        if not settings.CENTRAL_SERVER:
            raise CommandError("Disabled for distributed servers, until we can figure out what to do with ")

        options['platform'] = options['platform'].lower() # normalize

        if options['platform'] not in ["all", "linux", "macos", "darwin", "windows"]:
            raise CommandError("Unrecognized platform: %s; will include ALL files." % options['platform'])

        # Step 0: refresh all resources
        get_dubbed_video_map(force=True)  # force a remote download

        # Step 1: recursively add all static files
        kalite_base = os.path.realpath(settings.PROJECT_PATH + "/../")
        files_dict = recursively_add_files(dirpath=kalite_base, **options)

        # Step 2: Add a local_settings.py file.
        #   For distributed servers, this is a copy of the local local_settings.py,
        #   with a few properties (specified as command-line options) overridden
        ls_file = create_local_settings_file(location=os.path.realpath(kalite_base+"/kalite/local_settings.py"), server_type=options['server_type'], locale=options['locale'], central_server=options["central_server"])
        files_dict[ls_file] = { "dest_path": "kalite/local_settings.py" }

        # Step 3: select output file.
        if not options['file']:
            options['file'] = create_default_archive_filename(options)

        # Step 4: package into a zip file
        ensure_dir(os.path.realpath(os.path.dirname(options["file"])))  # allows relative paths to be passed.===
        system_specific_zipping(
            files_dict = dict([(v["dest_path"], src_path) for src_path, v in files_dict.iteritems()]),
            zip_file = options["file"],
            compression=ZIP_DEFLATED if options['compress'] else ZIP_STORED,
            callback=_default_callback_zip if options["verbosity"] else None,
        )
Beispiel #2
0
    def handle(self, *args, **options):

        options['platform'] = options['platform'].lower()  # normalize

        if options['platform'] not in [
                "all", "linux", "macos", "darwin", "windows"
        ]:
            raise CommandError(
                "Unrecognized platform: %s; will include ALL files." %
                options['platform'])

        # Step 0: refresh all resources
        if not settings.DEBUG:
            get_dubbed_video_map(force=True)  # force a remote download

        # Step 1: recursively add all static files
        kalite_base = os.path.realpath(settings.KALITE_PATH)
        files_dict = recursively_add_files(dirpath=kalite_base, **options)

        # Step 2: Add a local_settings.py file.
        #   For distributed servers, this is a copy of the local local_settings.py,
        #   with a few properties (specified as command-line options) overridden
        ls_file = create_local_settings_file(
            location=os.path.realpath(kalite_base +
                                      "/kalite/local_settings.py"),
            server_type=options['server_type'],
            locale=options['locale'],
            central_server=options["central_server"])
        files_dict[ls_file] = {"dest_path": "kalite/local_settings.py"}

        # Step 3: select output file.
        if not options['file']:
            options['file'] = create_default_archive_filename(options)

        # Step 4: package into a zip file
        ensure_dir(os.path.realpath(os.path.dirname(
            options["file"])))  # allows relative paths to be passed.===
        system_specific_zipping(
            files_dict=dict([(v["dest_path"], src_path)
                             for src_path, v in files_dict.iteritems()]),
            zip_file=options["file"],
            compression=ZIP_DEFLATED if options['compress'] else ZIP_STORED,
            callback=_default_callback_zip if options["verbosity"] else None,
        )
    def handle(self, *args, **options):

        # Get the zone, remove so we can pass the rest of the options
        #   to the zip procedure
        zone_id = options["zone_id"]
        del options["zone_id"]
        wrapper_filename = options["file"] or os.path.join(tempfile.mkdtemp(), "package_" + create_default_archive_filename(options))


        # Pre-zip prep #1:
        #   Create the json data file
        def create_json_file(include_data):
            central_server = Device.get_central_server()
            if not zone_id:
                models = [central_server] if central_server else []

            else:
                # Get a chain of trust to the zone owner.
                #   Because we're on the central server, this will
                #   simply be the central server, but in the future
                #   this would return an actual chain.
                logging.debug("Generating a zone invitation...")
                zone = Zone.objects.get(id=zone_id)
                chain = ChainOfTrust(zone=zone)
                assert chain.validate()
                new_invitation = ZoneInvitation.generate(zone=zone, invited_by=Device.get_own_device())
                new_invitation.save()  # keep a record of the invitation, for future revocation.  Also, signs the thing

                # This ordering of objects is a bit be hokey, but OK--invitation usually must be
                #   inserted before devicezones--but because it's not pointing to any devices,
                #   it's OK to be at the end.
                # Note that the central server will always be at the front of the chain of trust,
                #   so no need to explicitly include.
                models = chain.objects() + [new_invitation]

                #
                if include_data:
                    logging.debug("Serializing entire dataset...")
                    devices = Device.objects.by_zone(zone)
                    devicezones = DeviceZone.objects.filter(zone=zone)
                    models += list(devices) + list(devicezones)
                    models += engine.get_models(zone=zone, limit=None)  # get all models on this zone

            models_file = tempfile.mkstemp()[1]
            with open(models_file, "w") as fp:
                fp.write(engine.serialize(models))
            return models_file
        models_file = create_json_file(options["include_data"])

        # Pre-zip prep #2:
        #   Generate the INNER zip
        def create_inner_zip_file():
            zip_file = os.path.join(settings.MEDIA_ROOT, "zip", os.path.basename(create_default_archive_filename(options)))
            options["file"] = zip_file
            if settings.DEBUG or not os.path.exists(zip_file):  # always regenerate in debug mode
                call_command("zip_kalite", **options)
            if not os.path.exists(zip_file):
                raise CommandError("Failed to create kalite zip file.")
            return zip_file
        inner_zip_file = create_inner_zip_file()

        # Pre-zip prep #3:
        #   Create a file with the inner zip file signature.
        def create_signature_file(inner_zip_file):
            signature_file = os.path.splitext(inner_zip_file)[0] + "_signature.txt"
            logging.debug("Generating signature; saving to %s" % signature_file)
            if settings.DEBUG or not os.path.exists(signature_file):  # always regenerate in debug mode
                key = Device.get_own_device().get_key()
                chunk_size = int(2E5)  #200kb chunks
                signature = key.sign_large_file(inner_zip_file, chunk_size=chunk_size)
                with open(signature_file, "w") as fp:
                    fp.write("%d\n" % chunk_size)
                    fp.write(signature)
            return signature_file
        signature_file = create_signature_file(inner_zip_file)

        # Gather files together
        files_dict = {
            UpdateCommand.inner_zip_filename: inner_zip_file,
            UpdateCommand.signature_filename: signature_file,
            InitCommand.data_json_filename:   models_file,
        }

        # Pre-zip prep #4:
        #   Create the install scripts.
        def create_install_files(files_dict={}):
            install_files = {}  # need to keep track of, for later cleanup

            # Create clickable scripts: unix
            install_sh_file = self.install_py_file[:-3] + "_linux.sh"
            install_files[install_sh_file] = tempfile.mkstemp()[1]
            with open(install_files[install_sh_file], "w") as fp:
                fp.write("echo 'Searching for python path...'\n")
                with open(os.path.realpath(os.path.join(settings.KALITE_PATH, "scripts/python.sh")), "r") as pythonfp:
                    fp.write(pythonfp.read())
                fp.write('\ncurrent_dir=`dirname "${BASH_SOURCE[0]}"`')
                fp.write('\n$PYEXEC "$current_dir/%s"' % self.install_py_file)

            # Create clickable scripts: mac
            install_command_file = self.install_py_file[:-3] + "_mac.command"
            install_files[install_command_file] = tempfile.mkstemp()[1]
            with open(install_files[install_command_file], "w") as fp:
                fp.write('\ncurrent_dir=`dirname "${BASH_SOURCE[0]}"`')
                fp.write('\nsource "$current_dir/%s"' % install_sh_file)

            # Create clickable scripts: windows
            install_bat_file = self.install_py_file[:-3] + "_windows.bat"
            install_files[install_bat_file] = tempfile.mkstemp()[1]
            with open(install_files[install_bat_file], "w") as fp:
                fp.write("start /b /wait python.exe %s" % self.install_py_file)

            # Dump readme file
            readme_file = "README"
            install_files[readme_file] = tempfile.mkstemp()[1]
            with open(install_files[readme_file], "w") as fp:
                # First line of docstring is a message that the docstring will
                #   be the readme.  Remove that, dump the rest raw!
                fp.write(inspect.getdoc(install_from_package).split("\n", 2)[1])

            # NOTE: do this last, so we can pass the set of install files in the
            #   function call, for effective cleanup.

            # Create the install python script,
            #   by outputting the install_from_package function (extracting here
            #   through inspection and dumping line-by-line), and its dependencies
            #   (utils.platforms, grabbed here through force).
            #
            # Also output a call to the function.
            install_files[self.install_py_file] = tempfile.mkstemp()[1]
            with open(install_files[self.install_py_file], "w") as fp:
                for srcline in inspect.getsourcelines(install_from_package)[0]:
                    fp.write(srcline)
                fp.write("\n%s\n" % open(get_module_source_file("fle_utils.platforms"), "r").read())
                fp.write("\ninstall_from_package(\n")
                fp.write("    zip_file='%s',\n" % UpdateCommand.inner_zip_filename)
                fp.write("    signature_file='%s',\n" % UpdateCommand.signature_filename)
                fp.write("    data_json_file='%s',\n" % InitCommand.data_json_filename)
                fp.write("    install_files=%s,\n" % (files_dict.keys() + install_files.keys()))
                fp.write(")\n")
                fp.write("print 'Installation completed!'")

            return install_files
        install_files = create_install_files(files_dict=files_dict)

        # FINAL: Create the outer (wrapper) zip
        files_dict.update(install_files)
        system_specific_zipping(
            files_dict = files_dict,
            zip_file=wrapper_filename,
            compression=ZIP_STORED if settings.DEBUG else ZIP_DEFLATED,
#            callback=None,
        )

        # cleanup
        os.remove(models_file)
        for fil in install_files.values():
            os.remove(fil)

        sys.stdout.write("Successfully packaged KA Lite to %s.\n" % wrapper_filename)


        # To test:
        #   Unpack to a temporary folder, then run install
        if options["auto_unpack"]:
            def simulate_enduser_experience():
                # unpack the inner zip to the destination
                dest_dir = tempfile.mkdtemp()
                sys.stdout.write("TEST: Unpacking and installing to %s\n" % dest_dir)

                # Simulate a user unpacking the zip
                zip = ZipFile(wrapper_filename, "r")
                for afile in zip.namelist():
                    zip.extract(afile, path=dest_dir)

                # Simulate the user running the script
                raise NotImplementedError()
            simulate_enduser_experience()
Beispiel #4
0
    def handle(self, *args, **options):

        # Get the zone, remove so we can pass the rest of the options
        #   to the zip procedure
        zone_id = options["zone_id"]
        del options["zone_id"]
        wrapper_filename = options["file"] or os.path.join(
            tempfile.mkdtemp(),
            "package_" + create_default_archive_filename(options))

        # Pre-zip prep #1:
        #   Create the json data file
        def create_json_file(include_data):
            central_server = Device.get_central_server()
            if not zone_id:
                models = [central_server] if central_server else []

            else:
                # Get a chain of trust to the zone owner.
                #   Because we're on the central server, this will
                #   simply be the central server, but in the future
                #   this would return an actual chain.
                logging.debug("Generating a zone invitation...")
                zone = Zone.objects.get(id=zone_id)
                chain = ChainOfTrust(zone=zone)
                assert chain.validate()
                new_invitation = ZoneInvitation.generate(
                    zone=zone, invited_by=Device.get_own_device())
                new_invitation.save(
                )  # keep a record of the invitation, for future revocation.  Also, signs the thing

                # This ordering of objects is a bit be hokey, but OK--invitation usually must be
                #   inserted before devicezones--but because it's not pointing to any devices,
                #   it's OK to be at the end.
                # Note that the central server will always be at the front of the chain of trust,
                #   so no need to explicitly include.
                models = chain.objects() + [new_invitation]

                #
                if include_data:
                    logging.debug("Serializing entire dataset...")
                    devices = Device.objects.by_zone(zone)
                    devicezones = DeviceZone.objects.filter(zone=zone)
                    models += list(devices) + list(devicezones)
                    models += engine.get_models(
                        zone=zone, limit=None)  # get all models on this zone

            models_file = tempfile.mkstemp()[1]
            with open(models_file, "w") as fp:
                fp.write(engine.serialize(models))
            return models_file

        models_file = create_json_file(options["include_data"])

        # Pre-zip prep #2:
        #   Generate the INNER zip
        def create_inner_zip_file():
            zip_file = os.path.join(
                settings.MEDIA_ROOT, "zip",
                os.path.basename(create_default_archive_filename(options)))
            options["file"] = zip_file
            if settings.DEBUG or not os.path.exists(
                    zip_file):  # always regenerate in debug mode
                call_command("zip_kalite", **options)
            if not os.path.exists(zip_file):
                raise CommandError("Failed to create kalite zip file.")
            return zip_file

        inner_zip_file = create_inner_zip_file()

        # Pre-zip prep #3:
        #   Create a file with the inner zip file signature.
        def create_signature_file(inner_zip_file):
            signature_file = os.path.splitext(
                inner_zip_file)[0] + "_signature.txt"
            logging.debug("Generating signature; saving to %s" %
                          signature_file)
            if settings.DEBUG or not os.path.exists(
                    signature_file):  # always regenerate in debug mode
                key = Device.get_own_device().get_key()
                chunk_size = int(2E5)  #200kb chunks
                signature = key.sign_large_file(inner_zip_file,
                                                chunk_size=chunk_size)
                with open(signature_file, "w") as fp:
                    fp.write("%d\n" % chunk_size)
                    fp.write(signature)
            return signature_file

        signature_file = create_signature_file(inner_zip_file)

        # Gather files together
        files_dict = {
            UpdateCommand.inner_zip_filename: inner_zip_file,
            UpdateCommand.signature_filename: signature_file,
            InitCommand.data_json_filename: models_file,
        }

        # Pre-zip prep #4:
        #   Create the install scripts.
        def create_install_files(files_dict={}):
            install_files = {}  # need to keep track of, for later cleanup

            # Create clickable scripts: unix
            install_sh_file = self.install_py_file[:-3] + "_linux.sh"
            install_files[install_sh_file] = tempfile.mkstemp()[1]
            with open(install_files[install_sh_file], "w") as fp:
                fp.write("echo 'Searching for python path...'\n")
                with open(
                        os.path.realpath(
                            os.path.join(settings.KALITE_PATH,
                                         "scripts/python.sh")),
                        "r") as pythonfp:
                    fp.write(pythonfp.read())
                fp.write('\ncurrent_dir=`dirname "${BASH_SOURCE[0]}"`')
                fp.write('\n$PYEXEC "$current_dir/%s"' % self.install_py_file)

            # Create clickable scripts: mac
            install_command_file = self.install_py_file[:-3] + "_mac.command"
            install_files[install_command_file] = tempfile.mkstemp()[1]
            with open(install_files[install_command_file], "w") as fp:
                fp.write('\ncurrent_dir=`dirname "${BASH_SOURCE[0]}"`')
                fp.write('\nsource "$current_dir/%s"' % install_sh_file)

            # Create clickable scripts: windows
            install_bat_file = self.install_py_file[:-3] + "_windows.bat"
            install_files[install_bat_file] = tempfile.mkstemp()[1]
            with open(install_files[install_bat_file], "w") as fp:
                fp.write("start /b /wait python.exe %s" % self.install_py_file)

            # Dump readme file
            readme_file = "README"
            install_files[readme_file] = tempfile.mkstemp()[1]
            with open(install_files[readme_file], "w") as fp:
                # First line of docstring is a message that the docstring will
                #   be the readme.  Remove that, dump the rest raw!
                fp.write(
                    inspect.getdoc(install_from_package).split("\n", 2)[1])

            # NOTE: do this last, so we can pass the set of install files in the
            #   function call, for effective cleanup.

            # Create the install python script,
            #   by outputting the install_from_package function (extracting here
            #   through inspection and dumping line-by-line), and its dependencies
            #   (utils.platforms, grabbed here through force).
            #
            # Also output a call to the function.
            install_files[self.install_py_file] = tempfile.mkstemp()[1]
            with open(install_files[self.install_py_file], "w") as fp:
                for srcline in inspect.getsourcelines(install_from_package)[0]:
                    fp.write(srcline)
                fp.write("\n%s\n" % open(
                    get_module_source_file("fle_utils.platforms"), "r").read())
                fp.write("\ninstall_from_package(\n")
                fp.write("    zip_file='%s',\n" %
                         UpdateCommand.inner_zip_filename)
                fp.write("    signature_file='%s',\n" %
                         UpdateCommand.signature_filename)
                fp.write("    data_json_file='%s',\n" %
                         InitCommand.data_json_filename)
                fp.write("    install_files=%s,\n" %
                         (files_dict.keys() + install_files.keys()))
                fp.write(")\n")
                fp.write("print 'Installation completed!'")

            return install_files

        install_files = create_install_files(files_dict=files_dict)

        # FINAL: Create the outer (wrapper) zip
        files_dict.update(install_files)
        system_specific_zipping(
            files_dict=files_dict,
            zip_file=wrapper_filename,
            compression=ZIP_STORED if settings.DEBUG else ZIP_DEFLATED,
            #            callback=None,
        )

        # cleanup
        os.remove(models_file)
        for fil in install_files.values():
            os.remove(fil)

        sys.stdout.write("Successfully packaged KA Lite to %s.\n" %
                         wrapper_filename)

        # To test:
        #   Unpack to a temporary folder, then run install
        if options["auto_unpack"]:

            def simulate_enduser_experience():
                # unpack the inner zip to the destination
                dest_dir = tempfile.mkdtemp()
                sys.stdout.write("TEST: Unpacking and installing to %s\n" %
                                 dest_dir)

                # Simulate a user unpacking the zip
                zip = ZipFile(wrapper_filename, "r")
                for afile in zip.namelist():
                    zip.extract(afile, path=dest_dir)

                # Simulate the user running the script
                raise NotImplementedError()

            simulate_enduser_experience()