예제 #1
0
def main():
    parser = argparse.ArgumentParser(
        description="Statik, the static web site generator for developers."
    )
    parser.add_argument(
        '-p', '--project',
        help="The path to your Statik project (default: current directory).",
    )
    parser.add_argument(
        '-o', '--output',
        help="The output path into which to place the built project (default: \"public\" directory in input " +
             "directory).",
    )
    parser.add_argument(
        '--quickstart',
        help="Statik will generate a basic directory structure for you in the project directory.",
        action='store_true',
    )
    parser.add_argument(
        '-v', '--verbose',
        help="Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    args = parser.parse_args()
    project_path = args.project if args.project is not None else os.getcwd()
    output_path = args.output if args.output is not None else os.path.join(project_path, 'public')

    configure_logging(verbose=args.verbose)
    if args.quickstart:
        generate_quickstart(project_path)
    else:
        generate(project_path, output_path=output_path, in_memory=False)
예제 #2
0
    def test_issue(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, 'data-non-root-base'),
            in_memory=True
        )
        self.assertIn('albums', output_data)
        self.assertIn('browse', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['browse'])
        self.assertIn('test-album1', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['test-album1'])
        self.assertIn('test-album2', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['test-album2'])

        html = ET.fromstring(output_data['albums']['browse']['index.html'])
        self.assertEqual('Browse Albums', html.find('head/title').text.strip())
        album_els = [el for el in html.findall('body/ul/li/a')]
        self.assertEqual(2, len(album_els))
        self.assertEqual('Test Album 2', album_els[0].text.strip())
        self.assertEqual(
            '/non/standard/albums/test-album2/',
            album_els[0].attrib['href']
        )
        self.assertEqual('Test Album 1', album_els[1].text.strip())
        self.assertEqual(
            '/non/standard/albums/test-album1/',
            album_els[1].attrib['href']
        )
예제 #3
0
    def test_issue(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, 'data-non-root-base'),
            in_memory=True
        )
        self.assertIn('index.html', output_data)
        self.assertIn('about', output_data)
        self.assertIn('index.html', output_data['about'])
        self.assertIn('contact', output_data)
        self.assertIn('index.html', output_data['contact'])

        html = ET.fromstring(output_data['index.html'])
        static_page_links = html.findall("body/div[@class='menu']/ul/li/a")
        self.assertEqual(2, len(static_page_links))
        self.assertEqual('/non/standard/about/', static_page_links[0].attrib['href'])
        self.assertEqual('/non/standard/contact/', static_page_links[1].attrib['href'])

        self.assert_static_page_compiles(
            output_data['about']['index.html'],
            "About",
            "Here's the About page."
        )
        self.assert_static_page_compiles(
            output_data['contact']['index.html'],
            "Contact",
            "Here's how to contact us."
        )
예제 #4
0
    def test_in_memory(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(os.path.join(test_path, 'data-themed',
                                            'config-permalinks.yml'),
                               os.path.join(test_path, 'data-themed'),
                               in_memory=True)

        self.assertIn('index.html', output_data)
        self.assertIn('test', output_data)
        self.assertIn('index.html', output_data['test'])

        tree = ET.fromstring(_str(output_data['test']['index.html']))
        heading2 = tree.findall('./body/h2')[0]
        self.assertEqual('heres-a-heading', heading2.get('id'))
        permalink2 = tree.findall('./body/h2/a')[0]
        self.assertEqual('#heres-a-heading', permalink2.get('href'))
        self.assertEqual('permalink', permalink2.get('class'))
        self.assertEqual('Permalink to this heading', permalink2.get('title'))

        heading3 = tree.findall('./body/h3')[0]
        self.assertEqual('heres-another-sub-heading', heading3.get('id'))
        permalink3 = tree.findall('./body/h3/a')[0]
        self.assertEqual('#heres-another-sub-heading', permalink3.get('href'))
        self.assertEqual('permalink', permalink3.get('class'))
        self.assertEqual('Permalink to this heading', permalink3.get('title'))
예제 #5
0
    def test_in_memory(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(os.path.join(test_path, 'data-themed',
                                            'config-custom-md-exts.yml'),
                               os.path.join(test_path, 'data-themed'),
                               in_memory=True)

        self.assertIn('index.html', output_data)
        self.assertIn('test', output_data)
        self.assertIn('test-with-code', output_data)
        self.assertIn('index.html', output_data['test'])
        self.assertIn('index.html', output_data['test-with-code'])

        tree = ET.fromstring(output_data['test-with-code']['index.html'])
        self.assertEqual("Test post with some code",
                         tree.findall('./head/title')[0].text.strip())
        self.assertEqual("This should test the codehilite integration.",
                         tree.findall('./body/p')[0].text.strip())
        self.assertEqual("codehilite",
                         tree.findall('./body/pre')[0].get('class'))
        self.assertEqual("language-python",
                         tree.findall('./body/pre/code')[0].get('class'))

        self.assertEqual(
            "And now some more code, but in a different language:",
            tree.findall('./body/p')[1].text.strip())
        self.assertEqual("codehilite",
                         tree.findall('./body/pre')[1].get('class'))
        self.assertEqual("language-c",
                         tree.findall('./body/pre/code')[1].get('class'))
예제 #6
0
    def test_mustache_templating(self):
        test_path = os.path.dirname(os.path.realpath(__file__))

        # Run the Statik generator on our unit test data project, put the
        # result in memory
        output_data = generate(
            os.path.join(test_path, 'data-mustache'),
            in_memory=True
        )
        self.assert_homepage_compiles(output_data)
        self.assert_posts_compile(output_data)
    def test_self_referencing_models(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(os.path.join(test_path,
                                            "data-self-referencing"),
                               in_memory=True)

        self.assertIn('index.html', output_data)
        homepage = ET.fromstring(output_data['index.html'])
        parents = homepage.findall('body/ul/li')
        self.assertEqual('Parent 1', parents[0].text.strip())
        children = set([c.text.strip() for c in parents[0].findall('ul/li')])
        self.assertEqual({'Child 1.1', 'Child 1.2'}, children)

        self.assertEqual('Parent 2', parents[1].text.strip())
        children = set([c.text.strip() for c in parents[1].findall('ul/li')])
        self.assertEqual({'Child 2.1', 'Child 2.2'}, children)
    def test_self_referencing_models(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, "data-self-referencing"),
            in_memory=True
        )

        self.assertIn('index.html', output_data)
        homepage = ET.fromstring(output_data['index.html'])
        parents = homepage.findall('body/ul/li')
        self.assertEqual('Parent 1', parents[0].text.strip())
        children = set([c.text.strip() for c in parents[0].findall('ul/li')])
        self.assertEqual({'Child 1.1', 'Child 1.2'}, children)

        self.assertEqual('Parent 2', parents[1].text.strip())
        children = set([c.text.strip() for c in parents[1].findall('ul/li')])
        self.assertEqual({'Child 2.1', 'Child 2.2'}, children)
예제 #9
0
    def test_theme2(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, 'data-themed', 'config-theme2.yml'),
            os.path.join(test_path, 'data-themed'),
            in_memory=True,
        )

        self.assertIn('index.html', output_data)
        self.assertIn('override-me', output_data)
        self.assertIn('index.html', output_data['override-me'])

        # parse the home page
        homepage = ET.fromstring(output_data['index.html'])
        self.assertEqual('Home - Theme 2', homepage.findall('./head/title')[0].text.strip())
        self.assertEqual('/assets/theme2.css', homepage.findall('./head/link')[0].attrib['href'])

        self.check_override_page(output_data['override-me']['index.html'])
예제 #10
0
    def test_theme2(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, 'data-themed', 'config-theme2.yml'),
            os.path.join(test_path, 'data-themed'),
            in_memory=True,
        )

        self.assertIn('index.html', output_data)
        self.assertIn('override-me', output_data)
        self.assertIn('index.html', output_data['override-me'])

        # parse the home page
        homepage = ET.fromstring(output_data['index.html'])
        self.assertEqual('Home - Theme 2', homepage.findall('./head/title')[0].text.strip())
        self.assertEqual('/assets/theme2.css', homepage.findall('./head/link')[0].attrib['href'])

        self.check_override_page(output_data['override-me']['index.html'])
    def test_in_memory(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(
            os.path.join(test_path, 'data-themed', 'config-custom-md-exts.yml'),
            os.path.join(test_path, 'data-themed'),
            in_memory=True
        )

        self.assertIn('index.html', output_data)
        self.assertIn('test', output_data)
        self.assertIn('test-with-code', output_data)
        self.assertIn('index.html', output_data['test'])
        self.assertIn('index.html', output_data['test-with-code'])

        tree = ET.fromstring(_str(output_data['test-with-code']['index.html']))
        self.assertEqual("Test post with some code", tree.findall('./head/title')[0].text.strip())
        self.assertEqual(
            "This should test the codehilite integration.",
            tree.findall('./body/p')[0].text.strip()
        )
        self.assertEqual(
            "codehilite",
            tree.findall('./body/pre')[0].get('class')
        )
        self.assertEqual(
            "language-python",
            tree.findall('./body/pre/code')[0].get('class')
        )

        self.assertEqual(
            "And now some more code, but in a different language:",
            tree.findall('./body/p')[1].text.strip()
        )
        self.assertEqual(
            "codehilite",
            tree.findall('./body/pre')[1].get('class')
        )
        self.assertEqual(
            "language-c",
            tree.findall('./body/pre/code')[1].get('class')
        )
예제 #12
0
    def test_issue(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(os.path.join(test_path, 'data-non-root-base'),
                               in_memory=True)
        self.assertIn('albums', output_data)
        self.assertIn('browse', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['browse'])
        self.assertIn('test-album1', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['test-album1'])
        self.assertIn('test-album2', output_data['albums'])
        self.assertIn('index.html', output_data['albums']['test-album2'])

        html = ET.fromstring(output_data['albums']['browse']['index.html'])
        self.assertEqual('Browse Albums', html.find('head/title').text.strip())
        album_els = [el for el in html.findall('body/ul/li/a')]
        self.assertEqual(2, len(album_els))
        self.assertEqual('Test Album 2', album_els[0].text.strip())
        self.assertEqual('/non/standard/albums/test-album2/',
                         album_els[0].attrib['href'])
        self.assertEqual('Test Album 1', album_els[1].text.strip())
        self.assertEqual('/non/standard/albums/test-album1/',
                         album_els[1].attrib['href'])
예제 #13
0
    def test_issue(self):
        test_path = os.path.dirname(os.path.realpath(__file__))
        output_data = generate(os.path.join(test_path, 'data-non-root-base'),
                               in_memory=True)
        self.assertIn('index.html', output_data)
        self.assertIn('about', output_data)
        self.assertIn('index.html', output_data['about'])
        self.assertIn('contact', output_data)
        self.assertIn('index.html', output_data['contact'])

        html = ET.fromstring(output_data['index.html'])
        static_page_links = html.findall("body/div[@class='menu']/ul/li/a")
        self.assertEqual(2, len(static_page_links))
        self.assertEqual('/non/standard/about/',
                         static_page_links[0].attrib['href'])
        self.assertEqual('/non/standard/contact/',
                         static_page_links[1].attrib['href'])

        self.assert_static_page_compiles(output_data['about']['index.html'],
                                         "About", "Here's the About page.")
        self.assert_static_page_compiles(output_data['contact']['index.html'],
                                         "Contact",
                                         "Here's how to contact us.")
예제 #14
0
def main():
    parser = argparse.ArgumentParser(
        description="Statik: a static web site generator for developers.")
    parser.add_argument(
        '--version',
        help='Display version info for Statik',
        action='store_true',
    )
    parser.add_argument(
        '--quickstart',
        help=
        "Statik will generate a basic directory structure for you in the project directory and exit.",
        action='store_true',
    )
    parser.add_argument(
        '-p',
        '--project',
        help=
        "The path to your Statik project or project YAML configuration file (default: current directory).",
    )
    parser.add_argument(
        '-o',
        '--output',
        help=
        "The output path into which to place the built project (default: \"public\" directory in input "
        + "directory).",
    )
    parser.add_argument(
        '-w',
        '--watch',
        help=
        "Statik will watch the project path for changes and automatically regenerate the project. "
        + "This also runs a small HTTP server to serve your output files.",
        action='store_true',
    )
    parser.add_argument(
        '--host',
        help=
        "When watching a folder for changes (--watch), this specifies the host IP address or hostname to which "
        + "to bind (default: localhost).",
        default='localhost',
    )
    parser.add_argument(
        '--port',
        help=
        "When watching a folder for changes (--watch), this specifies the port to which to bind (default: 8000).",
        type=int,
        default=8000,
    )
    parser.add_argument(
        '-n',
        '--no-browser',
        action='store_true',
        default=False,
        help=
        "Do not attempt to automatically open a web browser at the served URL when watching for changes"
    )
    parser.add_argument(
        '-s',
        '--safe-mode',
        action='store_true',
        default=False,
        help="Run Statik in safe mode (which disallows unsafe query execution)"
    )
    parser.add_argument(
        '-v',
        '--verbose',
        help=
        "Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    args = parser.parse_args()

    try:
        _project_path = args.project if args.project is not None else os.getcwd(
        )
        project_path, config_file_path = get_project_config_file(
            _project_path, StatikProject.CONFIG_FILE)
        output_path = args.output if args.output is not None else os.path.join(
            project_path, 'public')

        configure_logging(verbose=args.verbose)
        if args.version:
            from statik import __version__
            logger.info('Statik v%s' % __version__)
        elif args.watch:
            watch(config_file_path,
                  output_path,
                  host=args.host,
                  port=args.port,
                  open_browser=(not args.no_browser),
                  safe_mode=args.safe_mode)
        elif args.quickstart:
            generate_quickstart(project_path)
        else:
            generate(config_file_path,
                     output_path=output_path,
                     in_memory=False,
                     safe_mode=args.safe_mode)

    except StatikError as e:
        logger.exception(
            "Exception caught while attempting to generate project", e)
        sys.exit(e.exit_code)

    except Exception as e:
        logger.exception(
            "Exception caught while attempting to generate project", e)
        sys.exit(1)

    # success
    sys.exit(0)
예제 #15
0
    def test_in_memory(self):
        test_path = os.path.dirname(os.path.realpath(__file__))

        # Run the Statik generator on our unit test data project, put the
        # result in memory
        output_data = generate(
            os.path.join(test_path, 'data-simple'),
            in_memory=True
        )

        # Check that the home page is there
        self.assertIn('index.html', output_data)

        # Check that the generated posts are there
        self.assert_path_exists("2016/06/12/andrew-hello-world/index.html", output_data)
        self.assert_path_exists("2016/06/18/second-post/index.html", output_data)
        self.assert_path_exists("2016/06/25/andrew-second-post/index.html", output_data)
        self.assert_path_exists("2016/06/30/tables-test/index.html", output_data)
        self.assert_path_exists("tag-testing/index.html", output_data)
        self.assert_path_exists("overlap/index.html", output_data)
        self.assert_path_exists("overlap/andrew-hello-world/index.html", output_data)
        self.assert_path_exists("overlap/my-first-post/index.html", output_data)
        self.assert_path_exists("overlap/second-post/index.html", output_data)
        self.assert_path_exists("overlap/andrew-second-post/index.html", output_data)

        # Check that the paged posts exist
        self.assert_path_exists("paged-posts/1/index.html", output_data)
        self.assert_path_exists("paged-posts/2/index.html", output_data)
        self.assert_path_exists("paged-posts/3/index.html", output_data)

        # Check that the homepage compiles properly
        self.assert_homepage_compiles(output_data['index.html'])

        # Check that the post "my-first-post" compiles properly
        self.assert_my_first_post_compiles(self.assert_path_exists("2016/06/15/my-first-post/index.html", output_data))

        # Check that the two bios compiled properly
        self.assert_michael_bio_compiles(self.assert_path_exists("bios/michael/index.html", output_data))
        self.assert_andrew_bio_compiles(self.assert_path_exists("bios/andrew/index.html", output_data))

        # Test the for-each context rendering
        self.assert_by_author_andrew_compiles(self.assert_path_exists("by-author/andrew/index.html", output_data))
        self.assert_by_author_michael_compiles(self.assert_path_exists("by-author/michael/index.html", output_data))

        # Test the custom template tags/filters functionality
        tt = ET.fromstring(output_data['tag-testing']['index.html'])
        self.assertEqual('html', tt.findall('.')[0].tag)
        para_tags = tt.findall('./body/p')
        self.assertEqual('Hello world!', para_tags[0].text.strip())
        self.assertEqual('an uppercase string', para_tags[1].text.strip())

        # Check the contents of the overlapping simple/complex views
        ov = ET.fromstring(output_data['overlap']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test', ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Overlap Test', ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(output_data['overlap']['andrew-hello-world']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test', ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Andrew says Hello World', ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(output_data['overlap']['my-first-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test', ov.findall('./head/title')[0].text.strip())
        self.assertEqual('My first post', ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(output_data['overlap']['second-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test', ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Second post', ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(output_data['overlap']['andrew-second-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test', ov.findall('./head/title')[0].text.strip())
        self.assertEqual("Andrew's Second Post", ov.findall('./body/h1')[0].text.strip())

        # Test the Markdown table generation
        tables = ET.fromstring(output_data['2016']['06']['30']['tables-test']['index.html'])
        self.assertEqual('html', tables.findall('.')[0].tag)
        headings = tables.findall("./body/div[@class='content']/table/thead/tr/th")
        self.assertEqual(3, len(headings))
        self.assertEqual(['Heading 1', 'Heading 2', 'Heading 3'], [el.text.strip() for el in headings])

        cells = tables.findall("./body/div[@class='content']/table/tbody/tr/td")
        self.assertEqual(6, len(cells))
        self.assertEqual(
            ['One', 'Two', 'Three', 'Four', 'Five', 'Six'],
            [el.text.strip() for el in cells]
        )

        # Now test for the pagination
        pp = ET.fromstring(output_data['paged-posts']['1']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 1 of 3', pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 1 of 3', pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            [
                '/2016/06/30/tables-test/',
                '/2016/06/25/andrew-second-post/'
            ],
            pp_links,
        )
        self.assertEqual(
            [
                'Testing Markdown tables',
                'Andrew\'s Second Post'
            ],
            pp_link_titles,
        )

        pp = ET.fromstring(output_data['paged-posts']['2']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 2 of 3', pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 2 of 3', pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            [
                '/2016/06/18/second-post/',
                '/2016/06/15/my-first-post/'
            ],
            pp_links,
        )
        self.assertEqual(
            [
                'Second post',
                'My first post'
            ],
            pp_link_titles,
        )

        pp = ET.fromstring(output_data['paged-posts']['3']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 3 of 3', pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 3 of 3', pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            [
                '/2016/06/12/andrew-hello-world/'
            ],
            pp_links,
        )
        self.assertEqual(
            [
                'Andrew says Hello World'
            ],
            pp_link_titles,
        )

        self.assert_mlalchemy_complex_path_view_compiles(output_data)
        self.assert_homepage_compiles(self.assert_path_exists("mlalchemy/posts/index.html", output_data))
예제 #16
0
파일: cmdline.py 프로젝트: pztrick/statik
def main():
    parser = argparse.ArgumentParser(
        description="Statik: a static web site generator for developers."
    )
    parser.add_argument(
        '--version',
        help='Display version info for Statik',
        action='store_true',
    )
    parser.add_argument(
        '--quickstart',
        help="Statik will generate a basic directory structure for you in the project directory and exit.",
        action='store_true',
    )
    parser.add_argument(
        '-p', '--project',
        help="The path to your Statik project or project YAML configuration file (default: current directory).",
    )
    parser.add_argument(
        '-o', '--output',
        help="The output path into which to place the built project (default: \"public\" directory in input " +
             "directory).",
    )
    parser.add_argument(
        '-w', '--watch',
        help="Statik will watch the project path for changes and automatically regenerate the project. " +
             "This also runs a small HTTP server to serve your output files.",
        action='store_true',
    )
    parser.add_argument(
        '--host',
        help="When watching a folder for changes (--watch), this specifies the host IP address or hostname to which " +
             "to bind (default: localhost).",
        default='localhost',
    )
    parser.add_argument(
        '--port',
        help="When watching a folder for changes (--watch), this specifies the port to which to bind (default: 8000).",
        type=int,
        default=8000,
    )
    parser.add_argument(
        '-n', '--no-browser',
        action='store_true',
        default=False,
        help="Do not attempt to automatically open a web browser at the served URL when watching for changes"
    )
    parser.add_argument(
        '-s', '--safe-mode',
        action='store_true',
        default=False,
        help="Run Statik in safe mode (which disallows unsafe query execution)"
    )
    parser.add_argument(
        '-v', '--verbose',
        help="Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    args = parser.parse_args()

    try:
        _project_path = args.project if args.project is not None else os.getcwd()
        project_path, config_file_path = get_project_config_file(_project_path, StatikProject.CONFIG_FILE)
        output_path = args.output if args.output is not None else os.path.join(project_path, 'public')

        configure_logging(verbose=args.verbose)
        if args.version:
            from statik import __version__
            logger.info('Statik v%s' % __version__)
        elif args.watch:
            watch(config_file_path, output_path, host=args.host, port=args.port, open_browser=(not args.no_browser),
                  safe_mode=args.safe_mode)
        elif args.quickstart:
            generate_quickstart(project_path)
        else:
            generate(config_file_path, output_path=output_path, in_memory=False, safe_mode=args.safe_mode)

    except StatikError as e:
        logger.exception("Exception caught while attempting to generate project", e)
        sys.exit(e.exit_code)

    except Exception as e:
        logger.exception("Exception caught while attempting to generate project", e)
        sys.exit(1)

    # success
    sys.exit(0)
예제 #17
0
def main():
    parser = argparse.ArgumentParser(
        description="Statik: a static web site generator for developers."
    )
    parser.add_argument(
        '-p', '--project',
        help="The path to your Statik project or project YAML configuration file (default: current directory).",
    )
    parser.add_argument(
        '--quickstart',
        help="Statik will generate a basic directory structure for you in the project directory and exit.",
        action='store_true',
    )
    parser.add_argument(
        '--autogen',
        help="Statik will generate default views and templates in the project directory for all the models.",
        action='store_true',
    )

    group_generate = parser.add_argument_group('static site generation')
    group_generate.add_argument(
        '-o', '--output',
        help="The output path into which to place the built project (default: \"public\" directory in input " +
             "directory).",
    )
    group_generate.add_argument(
        '--clear-output',
        action='store_true',
        help="Clears the output folder first prior to building the project. If watching " +
            "is initiated, this will only clear the output folder once-off."
    )
    group_generate.add_argument(
        '-s', '--safe-mode',
        action='store_true',
        default=False,
        help="Run Statik in safe mode (which disallows unsafe query execution)"
    )

    group_server = parser.add_argument_group('built-in server')
    group_server.add_argument(
        '-w', '--watch',
        help="Statik will watch the project path for changes and automatically regenerate the project. " +
             "This also runs a small HTTP server to serve your output files.",
        action='store_true',
    )
    group_server.add_argument(
        '--host',
        help="When watching a folder for changes (--watch), this specifies the host IP address or hostname to which " +
             "to bind (default: localhost).",
        default='localhost',
    )
    group_server.add_argument(
        '--port',
        help="When watching a folder for changes (--watch), this specifies the port to which to bind (default: 8000).",
        type=int,
        default=8000,
    )
    group_server.add_argument(
        '-n', '--no-browser',
        action='store_true',
        default=False,
        help="Do not attempt to automatically open a web browser at the served URL when watching for changes"
    )

    group_remote = parser.add_argument_group('remote publishing')
    group_remote.add_argument(
        '-u', '--upload',
        action='store',
        help="Upload project to remote location (supported: SFTP, netlify)",
    )

    group_remote.add_argument(
        '--netlify-site-id',
        action='store',
        help="Netlify site id to upload to. (--upload=netlify must be specified too)",
    )

    group_remote.add_argument(
        '-c', '--clear-remote',
        action='store_true',
        help="CAUTION: This will delete ALL files and subfolders in the remote folder before uploading the generated files. " + 
             "If the subsequent upload fails, your website will no longer be online."
    )

    group_info = parser.add_argument_group('information about Statik')
    group_info.add_argument(
        '-v', '--verbose',
        help="Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    group_info.add_argument(
        '--quiet',
        default=False,
        help="Run Statik in quiet mode, where there will be no output except upon error.",
        action='store_true'
    )
    group_info.add_argument(
        '--fail-silently',
        default=False,
        help="Only relevant if running Statik in quiet mode - if Statik encounters an error, the only indication "
             "of this will be in the resulting error code returned by the process. No other output will be given "
             "on the terminal.",
        action='store_true'
    )
    group_info.add_argument(
        '--no-colorlog',
        action='store_true',
        help="By default, Statik outputs logging data in colour. By specifying this switch, " +
             "coloured logging will be turned off."
    )
    group_info.add_argument(
        '--version',
        help='Display version info for Statik',
        action='store_true',
    )
    args = parser.parse_args()

    error_context = StatikErrorContext()
    try:
        _project_path = args.project if args.project is not None else os.getcwd()
        project_path, config_file_path = get_project_config_file(
            _project_path,
            StatikProject.CONFIG_FILE
        )
        output_path = args.output if args.output is not None else \
            os.path.join(project_path, 'public')

        configure_logging(
            verbose=args.verbose,
            quiet=args.quiet,
            fail_silently=args.fail_silently,
            colourise=not args.no_colorlog
        )

        if args.fail_silently and not args.quiet:
            logger.warning("Ignoring --fail-silently switch because --quiet is not specified")

        if args.version:
            show_version()
            sys.exit(0)

        if args.clear_output:
            shutil.rmtree(output_path, ignore_errors=True)
            logger.info("Cleared output path: %s", output_path)

        if args.watch:
            watch(
                config_file_path,
                output_path,
                host=args.host,
                port=args.port,
                open_browser=(not args.no_browser),
                safe_mode=args.safe_mode,
                error_context=error_context
            )
        elif args.quickstart:
            generate_quickstart(project_path)
        elif args.autogen:
            autogen(project_path)
        else:
            if args.host and '--host=localhost' in sys.argv[1:]:
                logger.warning("Ignoring --host argument because --watch is not specified")
            if args.port and '--port=8000' in sys.argv[1:]:
                logger.warning("Ignoring --port argument because --watch is not specified")
            if args.no_browser:
                logger.warning("Ignoring --no-browser argument because --watch is not specified")

            generate(
                config_file_path,
                output_path=output_path,
                in_memory=False,
                safe_mode=args.safe_mode,
                error_context=error_context
            )

        if args.upload and args.upload == 'SFTP':
                upload_sftp(
                    config_file_path,
                    output_path,
                    rm_remote=args.clear_remote
                )
        elif args.netlify_site_id and args.upload == 'netlify':
            if args.clear_remote:
                logger.warning("--clear-remote is not supported when uploading to Netlify")

            upload_netlify(
                output_path,
                args.netlify_site_id
            )
        else:
            if args.clear_remote:
                logger.warning("Ignoring --clear-remote switch because --upload is not specified")

            if args.netlify_site_id and args.upload != 'netlify' or args.netlify_site_id:
                logger.warning("Ignoring --netlify-site-id: --upload=netlify not specified")

            if args.upload:
                logger.warning("Upload format '{}' not supported".format(args.upload))

    except StatikError as e:
        sys.exit(e.exit_code)

    except Exception as e:
        logger.exception("Exception caught while attempting to generate project")
        sys.exit(1)

    # success
    sys.exit(0)
예제 #18
0
def main():
    parser = argparse.ArgumentParser(
        description="Statik, the static web site generator for developers."
    )
    parser.add_argument(
        '-p', '--project',
        help="The path to your Statik project or project YAML configuration file (default: current directory).",
    )
    parser.add_argument(
        '-o', '--output',
        help="The output path into which to place the built project (default: \"public\" directory in input " +
             "directory).",
    )
    parser.add_argument(
        '-w', '--watch',
        help="Statik will watch the project path for changes and automatically regenerate the project. " +
            "This also runs a small HTTP server to serve your output files.",
        action='store_true',
    )
    parser.add_argument(
        '--host',
        help="When watching a folder for changes (--watch), this specifies the host IP address or hostname to which " +
             "to bind (default: localhost).",
        default='localhost',
    )
    parser.add_argument(
        '--port',
        help="When watching a folder for changes (--watch), this specifies the port to which to bind (default: 8000).",
        type=int,
        default=8000,
    )
    parser.add_argument(
        '--quickstart',
        help="Statik will generate a basic directory structure for you in the project directory.",
        action='store_true',
    )
    parser.add_argument(
        '-v', '--verbose',
        help="Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    parser.add_argument(
        '--version',
        help='Display version info for Statik',
        action='store_true',
    )
    args = parser.parse_args()

    _project_path = args.project if args.project is not None else os.getcwd()
    project_path, config_file_path = get_project_config_file(_project_path, StatikProject.CONFIG_FILE)
    output_path = args.output if args.output is not None else os.path.join(project_path, 'public')

    configure_logging(verbose=args.verbose)
    if args.version:
        from statik import __version__
        logger.info('Statik v%s' % __version__)
    elif args.watch:
        watch(config_file_path, output_path, host=args.host, port=args.port)
    elif args.quickstart:
        generate_quickstart(project_path)
    else:
        generate(config_file_path, output_path=output_path, in_memory=False)
예제 #19
0
파일: watcher.py 프로젝트: tylerdave/statik
 def generate(self):
     generate(self.project_path, self.output_path, in_memory=False)
예제 #20
0
    def test_in_memory(self):
        test_path = os.path.dirname(os.path.realpath(__file__))

        # Run the Statik generator on our unit test data project, put the
        # result in memory
        output_data = generate(os.path.join(test_path, 'data-simple'),
                               in_memory=True)

        # Check that the home page is there
        self.assertIn('index.html', output_data)

        # Check that the generated .htaccess file is in the root of the output data
        self.assertIn('.htaccess', output_data)
        self.assertEqual(EXPECTED_HTACCESS_CONTENT,
                         output_data['.htaccess'].strip())

        # Check that the generated posts are there
        self.assert_path_exists(
            "2018/02/12/unicode-in-markdown-test/index.html", output_data)
        self.assert_path_exists("2018/01/20/test-datetime-format/index.html",
                                output_data)
        self.assert_path_exists("2016/06/12/andrew-hello-world/index.html",
                                output_data)
        self.assert_path_exists("2016/06/18/second-post/index.html",
                                output_data)
        self.assert_path_exists("2016/06/25/andrew-second-post/index.html",
                                output_data)
        self.assert_path_exists("2016/06/30/tables-test/index.html",
                                output_data)
        self.assert_path_exists("tag-testing/index.html", output_data)
        self.assert_path_exists("overlap/index.html", output_data)
        self.assert_path_exists("overlap/andrew-hello-world/index.html",
                                output_data)
        self.assert_path_exists("overlap/my-first-post/index.html",
                                output_data)
        self.assert_path_exists("overlap/second-post/index.html", output_data)
        self.assert_path_exists("overlap/andrew-second-post/index.html",
                                output_data)

        # Check that the paged posts exist
        self.assert_path_exists("paged-posts/1/index.html", output_data)
        self.assert_path_exists("paged-posts/2/index.html", output_data)
        self.assert_path_exists("paged-posts/3/index.html", output_data)
        self.assert_path_exists("paged-posts/4/index.html", output_data)

        # Check that the Unicode support for Markdown works as intended
        self.assert_unicode_content_compiles(output_data)

        # Check that the homepage compiles properly
        self.assert_homepage_compiles(output_data['index.html'])

        # Check that the post "my-first-post" compiles properly
        self.assert_my_first_post_compiles(
            self.assert_path_exists("2016/06/15/my-first-post/index.html",
                                    output_data))

        # Check that the two bios compiled properly
        self.assert_michael_bio_compiles(
            self.assert_path_exists("bios/michael/index.html", output_data))
        self.assert_andrew_bio_compiles(
            self.assert_path_exists("bios/andrew/index.html", output_data))

        # Test the for-each context rendering
        self.assert_by_author_andrew_compiles(
            self.assert_path_exists("by-author/andrew/index.html",
                                    output_data))
        self.assert_by_author_michael_compiles(
            self.assert_path_exists("by-author/michael/index.html",
                                    output_data))

        # Test the custom template tags/filters functionality
        tt = ET.fromstring(output_data['tag-testing']['index.html'])
        self.assertEqual('html', tt.findall('.')[0].tag)
        para_tags = tt.findall('./body/p')
        self.assertEqual('Hello world!', para_tags[0].text.strip())
        self.assertEqual('an uppercase string', para_tags[1].text.strip())

        # Check the contents of the overlapping simple/complex views
        ov = ET.fromstring(output_data['overlap']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test',
                         ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Overlap Test',
                         ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(
            output_data['overlap']['andrew-hello-world']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test',
                         ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Andrew says Hello World',
                         ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(
            output_data['overlap']['my-first-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test',
                         ov.findall('./head/title')[0].text.strip())
        self.assertEqual('My first post',
                         ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(output_data['overlap']['second-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test',
                         ov.findall('./head/title')[0].text.strip())
        self.assertEqual('Second post',
                         ov.findall('./body/h1')[0].text.strip())

        ov = ET.fromstring(
            output_data['overlap']['andrew-second-post']['index.html'])
        self.assertEqual('html', ov.findall('.')[0].tag)
        self.assertEqual('Overlap Test',
                         ov.findall('./head/title')[0].text.strip())
        self.assertEqual("Andrew's Second Post",
                         ov.findall('./body/h1')[0].text.strip())

        # Test the Markdown table generation
        tables = ET.fromstring(
            output_data['2016']['06']['30']['tables-test']['index.html'])
        self.assertEqual('html', tables.findall('.')[0].tag)
        headings = tables.findall(
            "./body/div[@class='content']/table/thead/tr/th")
        self.assertEqual(3, len(headings))
        self.assertEqual(['Heading 1', 'Heading 2', 'Heading 3'],
                         [el.text.strip() for el in headings])

        cells = tables.findall(
            "./body/div[@class='content']/table/tbody/tr/td")
        self.assertEqual(6, len(cells))
        self.assertEqual(['One', 'Two', 'Three', 'Four', 'Five', 'Six'],
                         [el.text.strip() for el in cells])

        # Now test for the pagination
        pp = ET.fromstring(output_data['paged-posts']['1']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 1 of 4',
                         pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 1 of 4',
                         pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            [
                '/2018/02/12/unicode-in-markdown-test/',
                '/2018/01/20/test-datetime-format/'
            ],
            pp_links,
        )
        self.assertEqual(
            [
                'Testing Unicode θ in Markdown content (issues #50 and #63)',
                'Testing DateTime format (as per issue #59)'
            ],
            pp_link_titles,
        )

        pp = ET.fromstring(output_data['paged-posts']['2']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 2 of 4',
                         pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 2 of 4',
                         pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            ['/2016/06/30/tables-test/', '/2016/06/25/andrew-second-post/'],
            pp_links,
        )
        self.assertEqual(
            ['Testing Markdown tables', 'Andrew\'s Second Post'],
            pp_link_titles,
        )

        pp = ET.fromstring(output_data['paged-posts']['3']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 3 of 4',
                         pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 3 of 4',
                         pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            ['/2016/06/18/second-post/', '/2016/06/15/my-first-post/'],
            pp_links,
        )
        self.assertEqual(
            ['Second post', 'My first post'],
            pp_link_titles,
        )

        pp = ET.fromstring(output_data['paged-posts']['4']['index.html'])
        self.assertEqual('html', pp.findall('.')[0].tag)
        self.assertEqual('Page 4 of 4',
                         pp.findall('./head/title')[0].text.strip())
        self.assertEqual('Page 4 of 4',
                         pp.findall('./body/h1')[0].text.strip())
        pp_els = pp.findall('./body/ul/li/a')
        pp_links = [el.attrib['href'] for el in pp_els]
        pp_link_titles = [el.text.strip() for el in pp_els]
        self.assertEqual(
            ['/2016/06/12/andrew-hello-world/'],
            pp_links,
        )
        self.assertEqual(
            ['Andrew says Hello World'],
            pp_link_titles,
        )

        self.assert_mlalchemy_complex_path_view_compiles(output_data)
        self.assert_homepage_compiles(
            self.assert_path_exists("mlalchemy/posts/index.html", output_data))
        self.assert_json_data_compiles(output_data)
        self.assert_generated_js_compiles(output_data)
예제 #21
0
def main():
    parser = argparse.ArgumentParser(
        description="Statik: a static web site generator for developers.")
    parser.add_argument(
        '--version',
        help='Display version info for Statik',
        action='store_true',
    )
    parser.add_argument(
        '--quickstart',
        help=
        "Statik will generate a basic directory structure for you in the project directory and exit.",
        action='store_true',
    )
    parser.add_argument(
        '-p',
        '--project',
        help=
        "The path to your Statik project or project YAML configuration file (default: current directory).",
    )
    parser.add_argument(
        '-o',
        '--output',
        help=
        "The output path into which to place the built project (default: \"public\" directory in input "
        + "directory).",
    )
    parser.add_argument(
        '-w',
        '--watch',
        help=
        "Statik will watch the project path for changes and automatically regenerate the project. "
        + "This also runs a small HTTP server to serve your output files.",
        action='store_true',
    )
    parser.add_argument(
        '--host',
        help=
        "When watching a folder for changes (--watch), this specifies the host IP address or hostname to which "
        + "to bind (default: localhost).",
        default='localhost',
    )
    parser.add_argument(
        '--port',
        help=
        "When watching a folder for changes (--watch), this specifies the port to which to bind (default: 8000).",
        type=int,
        default=8000,
    )
    parser.add_argument(
        '-n',
        '--no-browser',
        action='store_true',
        default=False,
        help=
        "Do not attempt to automatically open a web browser at the served URL when watching for changes"
    )
    parser.add_argument(
        '-s',
        '--safe-mode',
        action='store_true',
        default=False,
        help="Run Statik in safe mode (which disallows unsafe query execution)"
    )
    parser.add_argument(
        '-v',
        '--verbose',
        help=
        "Whether or not to output verbose logging information (default: false).",
        action='store_true',
    )
    parser.add_argument(
        '--quiet',
        default=False,
        help=
        "Run Statik in quiet mode, where there will be no output except upon error.",
        action='store_true')
    parser.add_argument(
        '--fail-silently',
        default=False,
        help=
        "Only relevant if running Statik in quiet mode - if Statik encounters an error, the only indication "
        "of this will be in the resulting error code returned by the process. No other output will be given "
        "on the terminal.",
        action='store_true')
    parser.add_argument(
        '--no-colorlog',
        action='store_true',
        help=
        "By default, Statik outputs logging data in colour. By specifying this switch, "
        + "coloured logging will be turned off.")
    parser.add_argument(
        '--clear-output',
        action='store_true',
        help=
        "Clears the output folder first prior to building the project. If watching "
        + "is initiated, this will only clear the output folder once-off.")
    args = parser.parse_args()

    error_context = StatikErrorContext()
    try:
        _project_path = args.project if args.project is not None else os.getcwd(
        )
        project_path, config_file_path = get_project_config_file(
            _project_path, StatikProject.CONFIG_FILE)
        output_path = args.output if args.output is not None else \
            os.path.join(project_path, 'public')

        configure_logging(verbose=args.verbose,
                          quiet=args.quiet,
                          fail_silently=args.fail_silently,
                          colourise=not args.no_colorlog)

        if args.fail_silently and not args.quiet:
            logger.warning(
                "Ignoring --fail-silently switch because --quiet is not specified"
            )

        if args.version:
            show_version()
            sys.exit(0)

        if args.clear_output:
            shutil.rmtree(output_path, ignore_errors=True)
            logger.info("Cleared output path: %s", output_path)

        if args.watch:
            watch(config_file_path,
                  output_path,
                  host=args.host,
                  port=args.port,
                  open_browser=(not args.no_browser),
                  safe_mode=args.safe_mode,
                  error_context=error_context)
        elif args.quickstart:
            generate_quickstart(project_path)
        else:
            generate(config_file_path,
                     output_path=output_path,
                     in_memory=False,
                     safe_mode=args.safe_mode,
                     error_context=error_context)

    except StatikError as e:
        sys.exit(e.exit_code)

    except Exception as e:
        logger.exception(
            "Exception caught while attempting to generate project")
        sys.exit(1)

    # success
    sys.exit(0)