Archive for February, 2009

Converting a site to use Cachefly for static content

Tuesday, February 24th, 2009

I recently needed to move static content from a live site to a cachefly account. Rather than go through the directories, looking for the resources (js/css/images) I needed to ftp, I thought, “Man, this sure sounds like it could be automated”.

The first step was to collect a list of items that needed ftping to cachefly. I know what you’re saying, “Use find!” In case Ben is reading this, find “searchs for files in a directory hierarchy” (that’s from find’s man page Ben). I wanted to separate the resources out so I ran three different invocations.

For javascripts and css, the invocation was nearly identical:

find . -name '*.js' > js.libs
find . -name '*.css' > css.libs

Images were a little trickier. Most of the images are static content, but some are user-generated, likely to change or be removed. These do not go up to the CDN (at least for now). The user-generated content is located under one directory (call it /images/usergen), so we simply need to exclude it from find’s search.

find -path '*images/usergen*' -prune -o -path . -iname '*.gif' -o -iname '*.jpg' -o -iname '*.png' > image.files

The important parts:

  • -path '*images/usergen*' -prune

    Remove any found items that contain images/usergen in the path name.

  • -o -path .

    Search within the current directory (the root of the project).

  • -iname '*.gif' -o -iname '*.jpg' -o -iname '*.png'

    Match, case-insensitive (-iname instead of -name), any files ending in gif, jpg, or png.

We are then left with three files, each line of which contains the path, relative to the project root, of each resource I want to upload. I created a simple php script to upload the images, maintaining the pathing, to cachefly. So an image with relative path /images/header/header_left.png would now be accessible at instance.cachefly.com/images/header/header_left.png.

So the images are now up on the CDN. Now we need our code to point there as well. Fortunately, most of the resources were prepended with a domain (stored in the global $live_site). So the src attribute of an image, for instance, would be src=”< ?= $live_site ?>/images/header/header_left.png”. Creating a $cachefly_site global, we now only need to find lines in our code that have a basic layout of “stuff……$live_site…stuff…..png” where stuff is (.*) in regex land. So we utilize two commands, find and egrep. Find locates files we want and egrep searches the found files for a regex that would locate the resources in the code.

So first, we build the regex. We know a couple elements that need to be present, and one that should not be present. Needed are live_site and a resource extension (js/css/jpg/png/gif), and not needed is the “images/usergen” path, as this points to user generated content. So the regex becomes:

'live_site([^images/usergen])+.+(png|gif|jpg|css|js)'

This is the arg for egrep (the -l switch means print the file names that have a match, rather than the lines of a file that match):

egrep -lr 'live_site([^images/usergen])+.+(png|gif|jpg|css|js)'

Now we need to tell egrep what files to search using find:

find . -name "*.php" -exec egrep -lr 'live_site([^images/usergen])+.+(png|gif|jpg|css|js)' {} \;

We then store this list of files into a shell variable:

export FILES=`find . -name "*.php" -exec egrep -lr 'live_site([^images/usergen])+.+(png|gif|jpg|css|js)' {} \;`

Now that we have the files we need, we can search and replace $live_site with $cachefly_site for resources. The goto command for search and replace is sed. The sed command will look generically like this:

sed -i 's/search/replace/g' FILE

We actually have two issues though. Due to the nature of the code, we have to account for the $live_site variable being passed in via the global keyword. So not only are we searching for resource files, but we also have to add $cachefly_site to the global lines to make sure $cachefly_site is defined within the function where output is generated.

Searching and replacing resource files is pretty easy:

sed -i '/live_site.+\|js\|css\|gif\|png\|jpg/s/live_site/cachefly_site/g' $FILES

$FILES, of course, came from our find/egrep call earlier. There is one catch to the regex used here. It is actually of a different generic form than mentioned above:

sed -i '/contains/s/search/replace/g' FILE

With this format, we put a condition on whether to replace text, meaning the regex in the “contains” portion must be matched before the search and replace is performed on that line.
So our sed above says if the line contains live_site, followed by anything, ending in one of the listed resources (\| means OR), then replace live_site with cachefly_stite. I left of the $ since its common to both variables.

Running the sed command replaces everything nicely, but when we reload the page, we see notices about $live_site being undefined and resources being pulled from the host and not cachefly. So we need to handle the global importing.

This one is a little tricker because we are not really replacing live_site with cachefly_site, but appending it to the list of imported globals. So a line like

global $foo, $bar, $live_site, $baz;

becomes

global $foo, $bar, $live_site, $cachefly_site, $baz;

The other trick is that the global line should not already contain $cachefly_site. We don’t need that redundancy. So, without further ado, the sed:

sed -i '/global.*live_site.*\(cachefly_site\)\{0\}/s/live_site/live_site,\$cachefly_site/g' $FILES

The “contains” portion matches the keyword global, followed by stuff, followed by live_site followed by stuff, with cachefly_site appearing exactly 0 times (denoted by \{0\}). This ensures we only replace live_site when cachefly_site is not in the line already.
The “search” portion is easy; search for live_site. The replace portion replaces live_site with live_site,$cachefly_site. This takes into account when live_site is followed by a comma or semi-colon so we don’t get syntax errors.

And that is basically how I converted a site to use cachefly for static content.

Re-assert The Federal Government’s Role As An Agent Of the Several States

Thursday, February 5th, 2009

A template for a resolution for you to send to your state legislature requiring the Federal Government to reign itself back into it’s Constitutional constraints and cease imposing its will on the States. Remember, the Federal Government is an agent of the States, not the other way around.

  • WHEREAS, the Tenth Amendment to the Constitution of the United States reads as follows: “The powers not delegated to the United States by the Constitution, nor prohibited by it to the States, are reserved to the States respectively, or to the people”; and
  • WHEREAS, the Tenth Amendment defines the total scope of federal power as being that specifically granted by the Constitution of the United States and no more; and
  • WHEREAS, the scope of power defined by the Tenth Amendment means that the federal government was created by the states specifically to be an agent of the states; and
  • WHEREAS, today, in 2009, the states are demonstrably treated as agents of the federal government; and
  • WHEREAS, many federal laws are directly in violation of the Tenth Amendment to the Constitution of the United States; and
  • WHEREAS, the Tenth Amendment assures that we, the people of the United States of America and each sovereign state in the Union of States, now have, and have always had, rights the federal government may not usurp; and
  • WHEREAS, Article IV, section 4, United States Constitution, says in part, “The United States shall guarantee to every State in this Union a Republican Form of Government”, and the Ninth Amendment states that “The enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people”; and
  • WHEREAS, the United States Supreme Court has ruled in New York v. United States, 112 S. Ct. 2408 (1992), that Congress may not simply commandeer the legislative and regulatory processes of the states; and
  • WHEREAS, a number of proposals from previous administrations and some now pending from the present administration and from Congress may further violate the Constitution of the United States.

THEREFORE – Be it resolved by the House of Representatives of the State of <STATE>, the Senate concurring, that:

  1. That the State of <STATE> hereby claims sovereignty under the Tenth Amendment to the Constitution of the United States over all powers not otherwise enumerated and granted to the federal government by the Constitution of the United States.
  2. That this Resolution serves as notice and demand to the federal government, as our agent, to cease and desist, effective immediately, mandates that are beyond the scope of these constitutionally delegated powers.
  3. That all compulsory federal legislation that directs states to comply under threat of civil or criminal penalties or sanctions or requires states to pass legislation or lose federal funding be prohibited or repealed.
  4. That the Secretary of State of the State of <STATE> transmit copies of this resolution to the President of the United States, the President of the United States Senate, the Speaker of the United States House of Representatives, the Speaker of the House and the President of the Senate of each state’s legislature and each Member of Congress from the State of <STATE>.

Replace “State of <STATE>” with your state or commonwealth and send it away. Or create this as a petition, gather signatures, then present it to your legislators. Take back your state from the Federal bureaucrats.