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
Beispiel #2
0
 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
    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")
                fp.write(open(os.path.realpath(settings.PROJECT_PATH + "/../scripts/python.sh"), "r").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("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")
                fp.write(
                    open(
                        os.path.realpath(settings.PROJECT_PATH +
                                         "/../scripts/python.sh"), "r").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("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()