Example #1
0
    def test_should_delete_files_and_folders_and_files_withing_sub_folders(
            self):
        # declare file paths
        tmp = tempfile.gettempdir()
        base = os.path.join(tmp, 'base_folder')
        filename = os.path.join(base, 'test.txt')
        subfolder = os.path.join(base, 'sub_folder')
        sub_file = os.path.join(subfolder, 'subtest.txt')

        # create file structure
        os.mkdir(base)
        os.mkdir(subfolder)
        file_put_contents(filename, 'Foo')
        file_put_contents(sub_file, 'Bar')

        try:
            # delete content of folder
            folder_delete_content(base)

            # folder should still exist
            self.assertTrue(os.path.isdir(base))

            # ...but folder should be empty
            self.assertTrue(folder_is_empty(base))
        finally:
            if os.path.isdir(base):
                shutil.rmtree(base)
Example #2
0
    def test_cleanup_should_remove_all_files_and_folders_that_are_not_within_the_cache(
            self):
        # create cache
        self.cache.add('index.html',
                       None,
                       None,
                       '<h1>Foo</h1>',
                       minify_html=False)
        self.cache.write()

        # create content the cache system is not aware of
        file_put_contents(os.path.join(settings.CACHE_ROOT, 'foo.html'), 'Foo')
        os.mkdir(os.path.join(settings.CACHE_ROOT, 'test'))
        os.mkdir(os.path.join(settings.CACHE_ROOT, 'test', 'foo'))
        file_put_contents(
            os.path.join(settings.CACHE_ROOT, 'test', 'bar.html'), 'Bar')

        # cleanup cache content
        self.cache.cleanup()

        # except for the cache content, everything else should be gone
        self.assertFalse(
            os.path.isfile(os.path.join(settings.CACHE_ROOT, 'foo.html')))
        self.assertFalse(
            os.path.isfile(
                os.path.join(settings.CACHE_ROOT, 'test', 'bar.html')))
        self.assertFalse(
            os.path.isdir(os.path.join(settings.CACHE_ROOT, 'test')))
        self.assertFalse(
            os.path.isdir(os.path.join(settings.CACHE_ROOT, 'test', 'foo')))
Example #3
0
    def _generate_file(self, filename):
        if not os.path.exists(settings.STATIC_ROOT):
            os.path.makedirs(settings.STATIC_ROOT)

        filename = os.path.join(settings.STATIC_ROOT, filename)
        file_put_contents(filename, ' ')
        self.filenames.append(filename)
        return filename
Example #4
0
    def test_should_set_file_mod_time(self):
        tmp = tempfile.gettempdir()
        filename = os.path.join(tmp, 'mtime_test')
        file_put_contents(filename, 'test')
        ts = datetime(2016, 10, 8, 13, 40, 13)
        file_set_mtime(filename, ts)

        ts_read = file_get_mtime(filename)
        self.assertEqual(ts, ts_read)
Example #5
0
    def test_should_overwrite_existing_file(self):
        file_put_contents(get_deploy_timestamp_filename(), 'hello world')
        save_deploy_timestamp()

        timestamp = datetime.strptime(
            file_get_contents(get_deploy_timestamp_filename()),
            '%Y-%m-%dT%H:%M:%S'
        )
        self.assertEqual(datetime.now(), timestamp)
Example #6
0
def save_deploy_timestamp():
    """
    Write the current timestamp to the timestamp file that stores the timestamp
    when the last deployment happened in ISO format.
    """
    ts = datetime.now()
    file_put_contents(get_deploy_timestamp_filename(),
                      ts.strftime(TIMESTAMP_FORMAT))
    return ts
Example #7
0
    def test_should_return_true_if_both_files_contain_the_same_content(self):
        tmp = tempfile.gettempdir()
        a = os.path.join(tmp, 'a.txt')
        file_put_contents(a, 'Hello World')

        tmp = tempfile.gettempdir()
        b = os.path.join(tmp, 'b.txt')
        file_put_contents(b, 'Hello World')

        self.assertTrue(is_same_file(a, b))
Example #8
0
    def test_should_return_false_if_folder_contains_files(self):
        tmp = tempfile.gettempdir()
        folder = os.path.join(tmp, 'not_empty_folder')
        filename = os.path.join(folder, 'test.txt')
        os.mkdir(folder)
        file_put_contents(filename, 'Foo')

        try:
            self.assertFalse(folder_is_empty(folder))
        finally:
            shutil.rmtree(folder)
Example #9
0
 def test_get_mtime_should_return_last_mod_time_of_file(self):
     base = tempfile.gettempdir()
     filename = os.path.join(base, 'foo')
     file_put_contents(filename, 'test')
     try:
         ts = datetime(2016, 11, 18)
         file_set_mtime(filename, ts)
         self.assertEqual(ts, self.cache.get_mtime(filename))
     finally:
         if os.path.isfile(filename):
             os.remove(filename)
Example #10
0
    def test_should_write_file_content_as_unicode(self):
        tmp = tempfile.gettempdir()
        filename = os.path.join(tmp, 'test.txt')
        content = unicode('Hello World')
        file_put_contents(filename, content)

        content_read = file_get_contents(filename)
        self.assertEqual(content_read, content)
        self.assertIsInstance(content_read, unicode)

        os.remove(filename)
Example #11
0
    def test_should_return_false_if_both_files_do_not_contain_the_same_content(
            self):
        tmp = tempfile.gettempdir()
        a = os.path.join(tmp, 'a.txt')
        file_put_contents(a, 'Hello Foo')

        tmp = tempfile.gettempdir()
        b = os.path.join(tmp, 'b.txt')
        file_put_contents(b, 'Hello Bar')

        self.assertFalse(is_same_file(a, b))
Example #12
0
 def _report_status(self):
     """
     Write status to status file.
     """
     file_put_contents(
         os.path.join(settings.PUBLIC_HTML_ROOT, self.STATUS_FILENAME),
         to_json({
             'totalRecords': self._total_records,
             'recordCounter': self._record_counter,
             'message': self._message,
             'stopped': self._stopped
         }))
Example #13
0
def _copy_file(src_path, dst_path, context):
    """
    Copy the given file to the given dest. path. The filename and it's
    content may be substituted.
    """
    if is_text_file(src_path):
        # text, substritute content against given context
        content = file_get_contents(src_path)
        content = _get_substituted_content(content, context)
        file_put_contents(dst_path, content)
    else:
        # binary, directly copy without substitution
        shutil.copyfile(src_path, dst_path)
Example #14
0
    def handle(self, *args, **options):
        """
        Run command.
        """
        # load source data
        filename = os.path.join(settings.CUBANE_PATH, 'rawdata', 'countries.json')
        json = decode_json(file_get_contents(filename))

        # generate xml file content
        xml = []
        xml.append('<?xml version="1.0" encoding="utf-8"?>')
        xml.append('<django-objects version="1.0">')
        for c in json:
            # country name(s)
            name = c.get('name')

            # num code
            num_code = c.get('ccn3')

            # calling code
            calling_code = c.get('callingCode')
            if len(calling_code) >= 1:
                calling_code = calling_code[0]
            else:
                calling_code = None

            # generate xml
            xml.append('  <object pk="%s" model="cubane.country">' % c.get('cca2'))
            xml.append('    <field type="CharField" name="name">%s</field>' % name.get('common').upper())
            xml.append('    <field type="BooleanField" name="flag_state">0</field>')
            xml.append('    <field type="CharField" name="printable_name">%s</field>' % name.get('common'))
            xml.append('    <field type="CharField" name="iso3">%s</field>' % c.get('cca3'))
            xml.append('    <field type="BooleanField" name="landlocked">%s</field>' % ('1' if c.get('landlocked') else '0'))
            if num_code:
                xml.append('    <field type="PositiveSmallIntegerField" name="numcode">%s</field>' % num_code)
            xml.append('    <field type="CharField" name="calling_code">%s</field>' % calling_code)
            xml.append('  </object>')
        xml.append('</django-objects>')

        # save to xml file (fixture)
        filename = os.path.join(settings.CUBANE_PATH, 'fixtures', 'cubane', 'country.xml')
        file_put_contents(filename, '\n'.join(xml))

        # import fixture file
        call_command('loaddata', 'cubane/country.xml', interactive=False)
Example #15
0
 def notify(cls):
     """
     Notify the task runner to be executed shortly.
     """
     file_put_contents(cls.get_signal_filename(), '1')
Example #16
0
 def test_should_return_none_if_incorrect_timestamp_format(self):
     file_put_contents(get_deploy_timestamp_filename(), 'not an ISO formatted timestamp')
     self.assertIsNone(load_deploy_timestamp())
Example #17
0
    def _store_font_data(self, font_declaration, descriptor):
        """
        Store the given font data within the store cache.
        """
        # get base path for font
        font_name = descriptor.font_name
        name = FontCache.get_unique_font_name(font_name)
        path = os.path.join(settings.CUBANE_FONT_ROOT, name)
        version = descriptor.version
        mtime = descriptor.mtime

        # create base path if it does not exist yet
        if not os.path.isdir(settings.CUBANE_FONT_ROOT):
            os.makedirs(settings.CUBANE_FONT_ROOT)

        # create folder if not exists yet
        if not os.path.isdir(path):
            os.mkdir(path)

        # download font files for each varient that has been declared and is
        # supported by the font and generate css font declaration code...
        css = []
        for variant in descriptor.variants:
            # extract key information from variant
            family = variant.get('fontFamily')
            font_weight = variant.get('fontWeight')
            font_style = variant.get('fontStyle')
            local = variant.get('local')

            # skip if not declared
            if not font_declaration.supports_variant_by_components(font_weight, font_style):
                continue

            # determine list of available font files, some may not be available
            # due to download errors...
            imports = []
            for ext in self.FONT_TYPES:
                filename = '%(name)s-%(version)s-%(weight)s-%(style)s.%(ext)s' % {
                    'name': name,
                    'version': version,
                    'weight': font_weight,
                    'style': font_style,
                    'ext': ext
                }
                font_path = os.path.join(path, filename)
                url = variant.get(ext)
                if self._download_font_file(url, font_path, mtime):
                    imports.append(
                        (
                            ext,
                            '/media/fonts/%s/%s' % (name, filename)
                        )
                    )
                else:
                    # unable to download file
                    if not settings.TEST: # pragma: no cover
                        sys.stderr.write(
                            ('ERROR: Unable to download font ' + \
                             'file from \'%s\'.\n') % url
                        )

            # generate font-declaration (css) for this variant...
            if len(imports) > 0:
                css.extend([
                    '/* %s %s %s latin */' % (font_name, font_weight, font_style),
                    '@font-face {',
                    '    font-family: \'%s\';' % family,
                    '    font-style: %s;' % font_style,
                    '    font-weight: %s;' % font_weight,
                    '    src: ' + ', '.join([
                        'local(\'%s\')' % local_name
                        for local_name
                        in local
                    ]) + ',',
                    ',\n'.join([
                        '         url(\'%s\') format(\'%s\')' % (url, ext)
                        for ext, url
                        in imports
                    ]) + ';',
                    '}\n'
                ])

        # write css file for the entire font, covering all variants...
        if len(css) > 0:
            css_filename = os.path.join(path, '%s.css' % name)
            file_put_contents(css_filename, '\n'.join(css))
            return True
        else:
            # if we failed, remove font folder and skip this font
            if os.path.isdir(path):
                folder_delete_content(path)
                os.rmdir(path)

            return False
Example #18
0
def save_resource_version_identifier(identifier):
    """
    Store resource version identifier with in website's deployment target folder.
    """
    file_put_contents(get_resource_version_filename(), identifier)
Example #19
0
 def test_should_generate_hash_for_file_with_content(self):
     tmp = tempfile.gettempdir()
     filename = os.path.join(tmp, 'content.txt')
     file_put_contents(filename, 'Hello World')
     self.assertEqual(self.CONTENT_FILE_HASH, get_file_hash(filename))
Example #20
0
 def test_should_generate_hash_for_empty_file(self):
     tmp = tempfile.gettempdir()
     filename = os.path.join(tmp, 'empty.txt')
     file_put_contents(filename, '')
     self.assertEqual(self.EMPTY_FILE_HASH, get_file_hash(filename))
Example #21
0
def resize_svg_image(filename,
                     dst_filename,
                     width,
                     height,
                     focal_point=None,
                     optimize=True,
                     crop=True,
                     prefix=None):
    """
    Scale the given vector image (SVG) to the given width and height and save
    the result as a new vector image as the given dest. filename. Vector
    images, such as SVG do not necessarily need to be resized, however they may
    contain bitmap data which we will scale accordingly. Any vector data and
    viewport information is preserved.

    In addition, we will prefix all id attribute values and internal references
    with a short prefix that is unique to the file. We do this in case we inline
    multiple SVG files into the actual websites and we do not want to have any
    identifiers and/or references colliding.

    Finally, we also remove any style from the SVG, since this may then become
    global to the document when we inline an SVG.
    """
    def _scale_image(data, width, height):
        """
        Scale given image data blog to fit the given width and height.
        """
        # open image data
        try:
            img = WandImage(blob=data)
        except NOT_AN_IMAGE_WAND_EXCEPTIONS:
            # not an image! -> ignore and leave as is
            return None

        # do not upscale!
        w, h = img.size
        if width > w or height > h:
            width = w
            height = h

        if width < 1:
            width = 1

        if height < 1:
            height = 1

        # calc. new width and height by fitting it into the
        # desired boundaries
        w, h = get_image_fitting(w, h, width, height)
        img.resize(w, h)

        # return image blob
        blob = io.BytesIO()
        img.strip()
        img.save(file=blob)
        return blob.getvalue()

    def _match_image(m):
        """
        Process SVG <image> tag. Only deal with base64 embedded image data and
        ignore external references.
        """
        # extract attributes
        attr = {}
        for attrname, value in re.findall(
                r'(?P<attrname>\w+)="(?P<value>.*?)"', m.group('attr')):
            attr[attrname] = value

        # get image data
        data = attr.get('href', '')
        href = re.match(r'^data:image\/(?P<fmt>\w+);base64,(?P<data>.*?)$',
                        data)
        data = None
        fmt = None
        if href:
            fmt = href.group('fmt')
            try:
                data = base64.b64decode(href.group('data'))
            except TypeError:
                # base64 decoding error! -> ignore and leave as is
                pass

        # scale embedded image down to the max. given width, hegiht is
        # determined by aspect ratio of the image...
        if data is not None:
            data = _scale_image(data, width, height)
            if data is not None:
                data = base64.b64encode(data)
                attr['href'] = 'data:image/%s;base64,%s' % (fmt, data)
                return '<image %s/>' % ' '.join([
                    '%s="%s"' % (name, value) for name, value in attr.items()
                ])

        # fallback -> leave as is
        return m.group(0)

    def _replace_images(svg):
        """
        Find any replace any references to images.
        """
        return re.sub(r'<image (?P<attr>.*?)(?P<tail>(/>)|(></image>))',
                      _match_image, svg)

    def _get_viewbox(xml):
        """
        Return the viewbox coordinates from the viewBox attribute on the svg tag.
        """
        # parse vieewBox attribute
        viewbox = xml.svg.get('viewBox', '')
        components = re.split(r'[\s,]', viewbox, 4)
        x, y, w, h = (0.0, 0.0, 64.0, 64.0)
        if len(components) == 4:
            try:
                x, y, w, h = [float(c) for c in components]
            except:
                pass

        # do not allow an invalid viewbox, default to square
        if h == 0.0:
            h = 1.0

        return x, y, w, h

    def _set_viewbox(xml, x, y, w, h):
        """
        Set the viewBox within the given SVG xml markup to the new dimensions
        as given.
        """
        # set viewBox
        xml.svg['viewBox'] = '%s %s %s %s' % (x, y, w, h)

        # rewrite enable-background style (not really used by many browsders,
        # but we want to be consistent)
        style = xml.svg.get('style', '')
        style = re.sub(
            r'enable-background:\s*new\s+([-.,\d]+)\s+([-.,\d]+)\s+([-.,\d]+)\s+([-.,\d]+);?',
            'enable-background:new %s %s %s %s;' % (x, y, w, h), style)
        xml.svg['style'] = style

    def _normalised(x):
        """
        Return integer of x, if x has no fraction component.
        """
        intx = int(x)
        return intx if intx == x else x

    def _scale_viewbox(xml, width, height):
        """
        Scale the viewBox to the new aspect ratio of the given width and height.
        """
        # get viewBox from current SVG
        x, y, w, h = _get_viewbox(xml)

        # make the target width the same with as the SVG. The target height
        # is adjusted based on the target aspect ratio
        if height == 0:
            height = 1
        ar = float(width) / float(height)
        width = w
        height = width / ar

        # determine new cropping area
        cropx, cropy, cropw, croph = get_image_crop_area(
            w, h, width, height, focal_point)

        # adjust to new (cropped) viewBox
        cropx += x
        cropy += y

        # normalise values to int if we do not have a fraction
        cropx = _normalised(cropx)
        cropy = _normalised(cropy)
        cropw = _normalised(cropw)
        croph = _normalised(croph)

        # apply new viewbox
        _set_viewbox(xml, cropx, cropy, cropw, croph)

    def _inline_style(xml):
        """
        Take embedded style and inline all style information.
        """
        # extract style
        style = ''
        for tag in xml.svg.find_all('style'):
            style += '\n'.join(tag.contents) + '\n'
            tag.decompose()

        # inline all collected style
        inline_style(xml.svg, parse_style(style))
        remove_attr(xml.svg, ['class'])

    def _get_prefix(filename, prefix):
        """
        Return a unique prefix to be used, if the given prefix is None. Since
        the prefix may be used as unique identifiers, they must start with
        a letter and cannot start with a number.
        """
        # generate hash based on filename
        if prefix is None:
            m = hashlib.sha224()
            m.update(filename)
            prefix = m.hexdigest()[:6]

        # if the first character is a number, it becomes a letter
        # between a-f depending on the number.
        if prefix:
            try:
                n = int(prefix[0])
                prefix = ['a', 'b', 'c', 'd', 'e', 'f'][n % 6] + prefix[1:]
            except ValueError:
                pass

        if prefix != '' and not prefix.endswith('_'):
            prefix += '_'

        return prefix

    def _prefix_ids(node, prefix):
        prefix_ids(node, prefix)

    # open svg file as text and replace embedded bitmap data
    markup = file_get_contents(filename)
    markup = _replace_images(markup)

    # load xml
    if optimize or crop:
        xml = BeautifulSoup(markup, 'xml')
    else:
        xml = None

    # is SVG?
    if xml and xml.svg:
        # crop
        if crop:
            _scale_viewbox(xml, width, height)

        if optimize:
            _inline_style(xml)
            _prefix = _get_prefix(dst_filename, prefix)
            _prefix_ids(xml, _prefix)
            if _prefix:
                xml.svg['data-prefix'] = _prefix[:-1]

        # render xml out
        if xml:
            markup = unicode(xml)

    # write output to target filename
    file_put_contents(dst_filename, markup)
Example #22
0
 def signal_running(cls):
     """
     Indicate that the task running is currently running by writing the
     current process identifier (pid) to the pid file.
     """
     file_put_contents(cls.get_pid_filename(), unicode(os.getpid()))