Archiv für die Kategorie ‘Coding’

GIT und die Datenbank

Mittwoch, 21. April 2010

Nach einer Anfrage von Nightfly hier eine kleine Anleitung wie man Datenbank-Änderungen auch mit GIT erfassen kann. GIT ist im Grunde nicht dazu gebaut Datenbanken zu synchronisieren. Man kann es aber mehr oder weniger dazu missbrauchen.
Dabei werden nicht die Änderungen erfasst, sondern jedes mal ein kompletter Dump erstellt. Wie gesagt, optimal ist das nicht, aber wer bei jedem Commit auch einen frischen MySQL Dump mit dabei haben möchte, kann folgendermaßen vorgehen:

Man erstellt eine .git/hooks/pre-commit Datei mit folgendem Inhalt:

1
2
3
4
5
#!/bin/sh
# pre-commit

mysqldump5 -u someUser --password=somePassword --add-drop-table someDatabaseName > dump.sql
git add dump.sql

Damit erhält man automatisch in jedem Commit eine aktuelle dump.sql.

Reguläre Ausdrücke in TypoScript

Mittwoch, 10. Februar 2010

TypoScript Variablen und Konstanten mit regulären Ausdrücken zu prüfen ist ein neues Feature ab TYPO3 Version 4.3.0. Leider ist dieses Feature nirgendwo dokumentiert und es finden sich auch keine Beispiele im Internet. Ich habe es nach einiger Frickelei allerdings hingekriegt.

Und zwar ging es darum Google Analytics Javascript Code in die Seite einzufügen, falls eine entsprechende Template-Konstante gesetzt ist. Und so gehts:

1
2
3
[globalString = LIT:{$GOOGLE_ANALYTICS_ID} = /UA-([0-9]+)-([0-9]+)/]
  # do something
[end]

Wichtig ist dabei, dass globalString reguläre Ausdrücke unterstützt und globalVar nicht. Die Konstante muss man dann weiterhin mit LIT in einen Literal “typisieren” und den regulären Ausdruck mit “/” umschließen.
Mit Quantoren scheint es allerdings ein paar Probleme zu geben: ([0-9]{2}) als letzter Ausdruck meiner Google Analytics ID hat funktioniert, ([0-9]{1,4}) hingegen nicht. :/

rsync bei TYPO3 Projekten

Dienstag, 09. Februar 2010

Wollte heute mal ein TYPO3 Projekt ganz unkompliziert über rsync/ssh auf den Webserver hochladen. Funktioniert ganz gut mit:

1
rsync -rulzPh -e 'ssh -ax' ./ ssh-user@ssh-host:/directory

Die Optionen sind -r für rekursiv, -u für update, -l für symbolische Links (erhalten), -z für Komprimierung, -P für –progress (Fortschrittsanzeige) und –partial (erlaubt anscheinend fortsetzen von Dateitransfers) und -h für “human readable” Formate. Mit -e schaltet man die Remote Shell um (da ich ja über SSH verbinde). Damit man aber nicht die ganzen Temp-Dateien und den sonstigen MacOS Filesystem-Mist mit transferiert, erstellt man am besten eine Datei, die zu exkludierende Dateien enthält. Diese hab ich “.rsync_exclude” genannt. Der Inhalt sieht dann wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# exclude this file
- .rsync_exclude

# exclude mac files
- .DS_Store
- ._*

# exclude git repository
- .git

# exclude typo3 temp files
- /public/typo3temp/*
- /public/typo3conf/temp_*

# exclude typo3 install file
- /public/typo3conf/ENABLE_INSTALL_TOOL

# exclude typo3 deprecation logs
- /public/typo3conf/deprecation_*

Nun muss man beim Aufruf einfach nur noch --exclude-from=.rsync_exclude anhängen und ab gehts!

Superfish Menüs im jQuery noConflict Modus

Montag, 08. Februar 2010

Hatte gerade ein paar Probleme mit Superfish jQuery Menüs und prototype.js auf der selben Webseite. Die Ursache ist, dass sich beide Javascript Bibliotheken um die Variable namens “$” streiten. Um jQuery das auszutreiben, kann man die Bibliothek in den noConflict Modus setzen:

1
jQuery.noConflict();

Nun hat man allerdings das Problem, dass die Superfish Menüs nicht mehr funktionieren, da diese alle noch “$” verwenden. Das muss jetzt durchgängig durch “jQuery” ersetzt werden. Wer Superfish/Supersubs im jQuery noConflict Modus braucht:

superfish.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * Superfish v1.4.8 - jQuery menu widget
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 *  http://www.opensource.org/licenses/mit-license.php
 *  http://www.gnu.org/licenses/gpl.html
 *
 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
 */


;(function(jQuery){
    jQuery.fn.superfish = function(op){

        var sf = jQuery.fn.superfish,
            c = sf.c,
            $arrow = jQuery(['<span class="',c.arrowClass,'"> &#187;</span>'].join('')),
            over = function(){
                var $$ = jQuery(this), menu = getMenu($$);
                clearTimeout(menu.sfTimer);
                $$.showSuperfishUl().siblings().hideSuperfishUl();
            },
            out = function(){
                var $$ = jQuery(this), menu = getMenu($$), o = sf.op;
                clearTimeout(menu.sfTimer);
                menu.sfTimer=setTimeout(function(){
                    o.retainPath=(jQuery.inArray($$[0],o.$path)>-1);
                    $$.hideSuperfishUl();
                    if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length&lt;1){over.call(o.$path);}
                },o.delay);
            },
            getMenu = function($menu){
                var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
                sf.op = sf.o[menu.serial];
                return menu;
            },
            addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
           
        return this.each(function() {
            var s = this.serial = sf.o.length;
            var o = jQuery.extend({},sf.defaults,op);
            o.$path = jQuery('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
                jQuery(this).addClass([o.hoverClass,c.bcClass].join(' '))
                    .filter('li:has(ul)').removeClass(o.pathClass);
            });
            sf.o[s] = sf.op = o;
           
            jQuery('li:has(ul)',this)[(jQuery.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
                if (o.autoArrows) addArrow( jQuery('>a:first-child',this) );
            })
            .not('.'+c.bcClass)
                .hideSuperfishUl();
           
            var $a = jQuery('a',this);
            $a.each(function(i){
                var $li = $a.eq(i).parents('li');
                $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
            });
            o.onInit.call(this);
           
        }).each(function() {
            var menuClasses = [c.menuClass];
            if (sf.op.dropShadows  && !(jQuery.browser.msie && jQuery.browser.version < 7)) menuClasses.push(c.shadowClass);
            jQuery(this).addClass(menuClasses.join(' '));
        });
    };

    var sf = jQuery.fn.superfish;
    sf.o = [];
    sf.op = {};
    sf.IE7fix = function(){
        var o = sf.op;
        if (jQuery.browser.msie && jQuery.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
            this.toggleClass(sf.c.shadowClass+'-off');
        };
    sf.c = {
        bcClass     : 'sf-breadcrumb',
        menuClass   : 'sf-js-enabled',
        anchorClass : 'sf-with-ul',
        arrowClass  : 'sf-sub-indicator',
        shadowClass : 'sf-shadow'
    };
    sf.defaults = {
        hoverClass  : 'sfHover',
        pathClass   : 'overideThisToUse',
        pathLevels  : 1,
        delay       : 800,
        animation   : {opacity:'show'},
        speed       : 'normal',
        autoArrows  : true,
        dropShadows : true,
        disableHI   : false,        // true disables hoverIntent detection
        onInit      : function(){}, // callback functions
        onBeforeShow: function(){},
        onShow      : function(){},
        onHide      : function(){}
    };
    jQuery.fn.extend({
        hideSuperfishUl : function(){
            var o = sf.op,
                not = (o.retainPath===true) ? o.$path : '';
            o.retainPath = false;
            var $ul = jQuery(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
                    .find('>ul').hide().css('visibility','hidden');
            o.onHide.call($ul);
            return this;
        },
        showSuperfishUl : function(){
            var o = sf.op,
                sh = sf.c.shadowClass+'-off',
                $ul = this.addClass(o.hoverClass)
                    .find('>ul:hidden').css('visibility','visible');
            sf.IE7fix.call($ul);
            o.onBeforeShow.call($ul);
            $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
            return this;
        }
    });

})(jQuery);

supersubs.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * Supersubs v0.2b - jQuery plugin
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 *  http://www.opensource.org/licenses/mit-license.php
 *  http://www.gnu.org/licenses/gpl.html
 *
 *
 * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
 * their longest list item children. If you use this, please expect bugs and report them
 * to the jQuery Google Group with the word 'Superfish' in the subject line.
 *
 */


;(function(jQuery){ // $ will refer to jQuery within this closure

    jQuery.fn.supersubs = function(options){
        var opts = jQuery.extend({}, jQuery.fn.supersubs.defaults, options);
        // return original object to support chaining
        return this.each(function() {
            // cache selections
            var $$ = jQuery(this);
            // support metadata
            var o = jQuery.meta ? jQuery.extend({}, opts, $$.data()) : opts;
            // get the font size of menu.
            // .css('fontSize') returns various results cross-browser, so measure an em dash instead
            var fontsize = jQuery('<li id="menu-fontsize">&#8212;</li>').css({
                'padding' : 0,
                'position' : 'absolute',
                'top' : '-999em',
                'width' : 'auto'
            }).appendTo($$).width(); //clientWidth is faster, but was incorrect here
            // remove em dash
            jQuery('#menu-fontsize').remove();
            // cache all ul elements
            $ULs = $$.find('ul');
            // loop through each ul in menu
            $ULs.each(function(i) {
                // cache this ul
                var $ul = $ULs.eq(i);
                // get all (li) children of this ul
                var $LIs = $ul.children();
                // get all anchor grand-children
                var $As = $LIs.children('a');
                // force content to one line and save current float property
                var liFloat = $LIs.css('white-space','nowrap').css('float');
                // remove width restrictions and floats so elements remain vertically stacked
                var emWidth = $ul.add($LIs).add($As).css({
                    'float' : 'none',
                    'width' : 'auto'
                })
                // this ul will now be shrink-wrapped to longest li due to position:absolute
                // so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
                .end().end()[0].clientWidth / fontsize;
                // add more width to ensure lines don't turn over at certain sizes in various browsers
                emWidth += o.extraWidth;
                // restrict to at least minWidth and at most maxWidth
                if (emWidth > o.maxWidth)       { emWidth = o.maxWidth; }
                else if (emWidth < o.minWidth)  { emWidth = o.minWidth; }
                emWidth += 'em';
                // set ul to width in ems
                $ul.css('width',emWidth);
                // restore li floats to avoid IE bugs
                // set li width to full width of this ul
                // revert white-space to normal
                $LIs.css({
                    'float' : liFloat,
                    'width' : '100%',
                    'white-space' : 'normal'
                })
                // update offset position of descendant ul to reflect new width of parent
                .each(function(){
                    var $childUl = jQuery('>ul',this);
                    var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
                    $childUl.css(offsetDirection,emWidth);
                });
            });
           
        });
    };
    // expose defaults
    jQuery.fn.supersubs.defaults = {
        minWidth        : 9,        // requires em unit.
        maxWidth        : 25,       // requires em unit.
        extraWidth      : 0         // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
    };
   
})(jQuery); // plugin code ends

Erstellen von GIT Repositories

Donnerstag, 04. Februar 2010

Um mit GIT lokal zu arbeiten, genügt eigentlich der einfache Shell-Befehl:

1
git init

Um aber verteilt mit mehreren Entwicklern und verschiedenen Rechnern zu arbeiten, erstellt man am besten ein zentrales Repository auf einem Server mit:

1
git init --bare

Danach können sich die einzelnen Entwickler wie folgt in das Repository einklinken:

1
git clone ssh://user@host/dir/repository

Danach kann man mit

1
git pull

bzw.

1
git push

Revisionen holen bzw. einspielen.
Insbesondere beim ersten Mal muss man dabei die Quelle und den Branch angeben:

1
git pull origin master