Pixel picture of me Dan's Shorts
Valid XHTML 1.0 Valid CSS No tables fer you! Valid RSS
Steal This Button Macromedia Dreamweaver Macromedia Fireworks MX 2004 I Heart Music
Cartweaver
« July 2008 »
Su M T W Th F Sa Wk
29 30 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 12 

Monday, July 21, 2008

2:12 PM

Managing the Transfer Cache with Clones

In my recent adventures with Transfer, I ran into a problem where objects that weren't yet saved were showing up in my cached Transfer objects. Since I don't make mistakes (uh huh...) I immediately assumed this was a bug in Transfer, and went about documenting my problem on the Transfer group.

Well it turns out (surprise surprise) that this was by design, and so I had to make a few changes to my way of thinking in order to get my app to behave the way I expected it to. So here's a rundown of the "problem" and what was done to fix it (thanks to Matt Quackenbush for the fix).

How's the Cache Work?

Basically the Transfer cache keeps track of everything you do to an object, whether it's cached or not. This means that when I create a new object, it's immediately stored in the cache for each retrieval, and if I assign that object to a parent, it's stored with that parent in the cache, even before it gets saved.

My initial reaction to this was that it was bad behavior, but after ruminating over the possibilities, I changed my mind entirely. Being able to store complete transfer objects in cache by default would make it easy to do things like multi-page forms or shopping cart and order entry systems without needing to deal with the caching mechanism for it myself (such as putting an object in session).

The only issue is that if you do this, other parts of the application that can also see that object see non-saved data before you're ready for them to. That's alright if each user has their own unique "thing" that they're dealing with, but it's a big problem if people are sharing objects and data shouldn't be shared until it's validated and saved.

So What's my Problem

I have a Group object, which contains multiple Items. In my application, as part of the process of adding a new Item to a Group, I'm creating an empty Item object, and then assigning it to the right Group before I do anything else. The View then gets this object and the user can manipulate the empty and unsaved object. When the user clicks the Add button, the Item object is validated and then saved to the database if there are no errors. Here's the relevant bit of code that handles this:

<cffunction name="addItem" access="public" returntype="void" output="false">
	<cfargument name="Event" type="coldbox.system.beans.requestContext">

	<cfset var rc = Event.getCollection() />
	<cfset var LOCAL = StructNew() />

	<!--- Pass the group ID in in order to assign the item to the proper group --->
	<cfset rc.Item = variables.objectFactory.getBean("ItemService").getItem(
			rc.GroupID
			, 0) />

	<!--- Even if a blank object came back, be sure to set the group ID correctly --->
	<cfset rc.Item.setParentGroup(
			variables.objectFactory.getBean("GroupService").getGroup(
				Session.UserID, rc.GroupID)) />

	<cfset rc.Success = False />
	<cfif IsDefined("rc.do") AND rc.do EQ "additem">
		<cfset LOCAL.errors = ArrayNew(1) />

		<!--- Populate User with data --->
		<cfset getPlugin("beanFactory").populateBean(rc.Item) />

		<cfset LOCAL.result = variables.objectFactory.getBean("ItemService").save(rc.Item) />

		<cfif LOCAL.result.results>
			<cfset getPlugin("messagebox").setMessage(
					type="info"
					, message="Item Added!") />
			<cfset rc.Success = True />

		<cfelse>
			<cfset getPlugin("messagebox").setMessage(
					type="error"
					, message= ArrayToList(LOCAL.result.errors, "<br />")) />

		</cfif>
	</cfif>

	<cfset Event.setView("ajax/additem") />

</cffunction>

When I go to my ItemService, grab an Item, and then set it's Parent Group using the setParentGroup method, Transfer updates the Group object in the cache with the new (non-saved) Item. If an error occurs later in the flow during my ItemService.Save method, then the item still stays in the cache, and I end up with an empty Item for every new Item that doesn't pass validation

Cloning to the Rescue

So to fix this problem we can use a clone of an object to do our manipulations before we save it into the database. According to the Transfer ORM documentation, the Clone() method on an object allows you to "... to make a deep clone of every generated TransferObject ...". This newly cloned object is "... outside of any caching that is currently in use within Transfer, which means that any changes that are done to this object, and are not saved, are only particular to the request that they are currently in." In addition to that, the really slick part is "...that Transfer.save() and Transfer.update() on a clone object will update the object currently in cache to the state of the saved object."

Exactly what I need... So with that information in hand, I changed just two lines of code, and the problem was fixed:

<!--- Pass the group ID in in order to assign the item to the proper group --->
<cfset rc.Item = variables.objectFactory.getBean("ItemService").getItem(
		rc.GroupID
		, 0).Clone() />

<!--- Even if a blank object came back, be sure to set the group ID correctly --->
<cfset rc.Item.setParentGroup(
		variables.objectFactory.getBean("GroupService").getGroup(
			Session.UserID, rc.GroupID).Clone()) />

You should notice that I chained a Clone() method onto each of the getXXX methods in my services. This means that I get a deep copy of each to perform my operations. So when an error happens, it's happening to the objects in the current request, and not on the objects in the cache. As soon as I call the Service.Save method, validate the object, and then call he Transfer.Save method, all of the cache'd objects get magically updated for me so that they're available through the entire application.

And that's it... So the rule of thumb is, if you don't want your objects updated into the cache until they're saved, always use a Clone'd copy of them.

Posted by Dan | Comments (1) | Add Comment | Permalink

Comment from Bob Silverberg on 7/21/2008
Great post, Dan. Based on the recent conversation on the Transfer google group, I was just thinking that we needed a blog post explaining about clone(). I imagine there are many Transfer users who are unaware of its importance.

Just one thing I wanted to add; in your addItem function you're doing a great job of keeping Transfer decoupled from this object by using your ItemService. However, this new change now tightly couples this component with Transfer because you're calling clone() directly. I would consider looking at the getItem() method of your ItemService to see whether you can move the clone() into it.

Oh, and what's up with the ASP blog software? Shame on you ;-)

<reply>
Thanks for the compliment.

True that I've now required my Service to implement a Clone method for my controller to work... Just have to think this through and figure out if there would be times that I wouldn't want a clone back, and should that be an argument to my getXXX methods in my Service layer...

Good catch.

As for the ASP blog, the first post was made in July of 2002 (6 years ago!) and I've never had a reason to change it. It will eventually be converted to CF once I have by CCT chops honed :).
</reply>

 

Sunday, July 20, 2008

9:34 AM

Dealing with Stamp and StampUpdated with Transfer

Continuing work on my top secret app and learning CCT (ColdBox, ColdSpring, and Transfer), I'm going to describe how to handle stamp and stampupdated columns in your tables.

In every table that I have in any database I build, I have both a stamp and stampupdated column. The stamp column tells me when the record was originally created, and the stampupdated column tells me the last time that data changed. Both of these columns have a default value of getDate(). Here's the colum definition for an example table:

CREATE TABLE [dbo].MyTable(
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[Label] [varchar](50) NOT NULL,
	[stamp] [datetime] NOT NULL CONSTRAINT [DF_Items_stamp]  DEFAULT (getdate()),
	[stampupdated] [datetime] NOT NULL CONSTRAINT [DF_Items_stampupdated]  DEFAULT (getdate()),

This works great on initial insert, but doesn't update the stampupdated column on each UPDATE. So to handle making sure the stampupdated gets taken care of properly I create a trigger on each table like so:

CREATE TRIGGER [dbo].[MyTable_Update] 
   ON  [dbo].[MyTable]
   AFTER UPDATE
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	UPDATE MyTable
	SET stampupdated = getDate()
	FROM Inserted
	WHERE MyTable.ID = Inserted.ID

END

Now to handle these properly in Transfer, I can't have transfer updating and inserted those values, because the database is responsible for those actions. So let's take a look at what would be the standard property tags for those two columns:

<property name="stamp" type="date" column="stamp" />
<property name="stampupdated" type="date" column="stampupdated" />

So with the above property tags, when I save a transfer object it's going to run either an INSERT or an UPDATE statement that will change the stamp and stampupdated columns. But since the database is responsible for this data, that means that 1) Transfer is doing unnecessary and potentially incorrect work and 2) That the values that the database creates won't get back to the Transfer object. To fix that we need to add a few additional attributes to each of these property tags.

<property name="stamp" type="date" column="stamp" 
	ignore-insert="true" refresh-insert="true" 
	ignore-update="true" />
<property name="stampupdated" type="date" column="stampupdated" 
	ignore-insert="true" refresh-insert="true" 
	ignore-update="true" refresh-update="true" />

I've now told Transfer to ignore the stamp for the purposes of INSERTs and UPDATEs, and to update the Transfer value when a new record is inserted. I don't need to refresh the value on UPDATE, as the stamp value should never change.

On the stampupdated column however, I'm ignoring the value for both INSERTs and UPDATEs, and I'm also refreshing the value on both. This means that on an update the workflow of the UPDATE works something like this:

  1. Call Transfer save method
  2. Record is UPDATEd in the database
  3. On UPDATE trigger fires and updates stampupdated column to the current date
  4. Transfer queries the update record, picks up the new stampupdated column, and updates the stampupdated property of the object to the new value
  5. Transfer gives me back a fresh object with the new values

So that's how I handle all of my stamp and stampupdated columns in my database. You can find out more about the Transfer config options at the Transfer ORM docs site.

Posted by Dan | Comments (0) | Add Comment | Permalink

 

Saturday, July 19, 2008

11:15 AM

Creating Snippets in Eclipse

As I'm working with ColdBox, I was reminded just how handy snippets and trigger text can be. ColdBox has a metric ton of snippets available for CFEclipse, most of them with trigger text all ready to go. So I wanted to take a moment to go through how you can create your own snippets and trigger text to speed up common operations

When to use snippets

Sometimes it's just not worth writing a snippet. I could go nuts and create one for every CF function, but in the end I'd spend more time trying to remember my trigger text than I would coding. So building a snippet for a <cfset&cfgt; probably isn't worth your time, but building a snippet for a multi-line piece of code that you write constantly can save you a ton of time. Take the following code as an example:

<tr>
	<th><label for="MyID">Form Label: </label></th>
	<td><cfinput 
		type="text" 
		name="MyName" 
		id="MyID" 
		value="#MyObject.getMyName()#" /></td>
</tr>

That's a common piece of code to drop into a form for saving an object back to the database, and entering those lines over and over again for each and every property of the object is both time-consuming and error-prone. The perfect job for a snippet.

Retooling the Code

Before actually opening the Snippets view and starting to add a new snippet, I usually take the code I want to create as a snippet, and rework it directly in CFEclipse before copy/pasting it into the Snippet view. The New Snippet dialog is cramped and hard to work in, so this makes the process a little smoother. Here's what my code looks like after refactoring it for use as a Snippet:

<tr>
	<th><label for="$${ID}">$${Label}: </label></th>
	<td><cfinput 
		type="$${Type:text|hidden|password|radio|checkbox}" 
		name="$${Name}" 
		id="$${ID}" 
		value="$${Value}" /></td>
</tr>

Notice that I've replaced each of the changeable values of my original code to a Snippet variable. Replace name="MyName" with name="$${Name}" will cause Eclipse to display a dialog for me to fill in the blanks when I insert the snippet. Also, the type Snippet variable is followed by a pipe separate list of prefilled values that I can choose from when I insert this snippet, making it even less error prone and fast.

Creating the Snippet

Now that I have my code ready to go, I can create my snippet. The first thing to do is to make sure you have the Snip Tree View panel available to you in Eclipse. You can enable this view by choose Window > Show View > Other, and then choosing Snip Tree View from the CFML category. After that's complete you should see your Snip Tree View and you can drag it wherever you'd like within the interface.

Snip Tree View

To keep things organized you click click the box looking icon (Create a new snip package) in the toolbar for the panel to create new folders. I'm going to create a Layout folder and then a Forms folder to hold my new snippet. After creating the new folders, select the Forms folder and click the Plus icon to create a new Snippet.

New Snippet Dialog

You can see there's a lot of information here to work with:

  1. Snippet Name: this will display in the Snippets panel so you can easily find your newly created workflow enhancer
  2. Trigger Text: the Trigger Text value is a short value that you can use in Eclipse to quickly add the snippet using a shortcut key. I'll cover that at the end.
  3. Snippet Description: A description of just what this snippet does.
  4. Snippet start block: If your snippet is designed to wrap around something, this is what would go before the selection in the Eclipse editor window. If your snippet isn't design to wrap around something, this is where you'll put the full text of your snippet.
  5. Snippet closing block: The closing block of your snippet, if it has one.
  6. Use this snippet as a file template: You can actually create entire files from a single snippet. I've been using these to create my base Gateways and Service objects so that I don't have to type as much, and I never forget the code that every single one of them needs.
  7. Template extension: If you're going to create a file template, this is the file extension it'll get

So now that we know all of that information. This is what my newly created snippet is going to look like with the dialog completed:

Completed Snippet Dialog

Using the Snippet

There are two ways to use snippets. The first is by simply finding it in the Snip Tree view and double clicking the snippet. This is how you'll have to do use if you have a snippet that has a start and closing block and you want it to wrap around your current selection. The second way is to use the trigger text (my preferred method).

To use snippet trigger text, simply type the trigger text (in our case inprow) into the Eclipse editor, and with the cursor at the end of the trigger text, press Ctrl/Cmd + J to activate the snippet. Now you should see the snippet dialog with fields for each of the variables you declared:

Replace Variables dialog

Now just complete the form and click OK and you have all of your code complete and ready to go:

Completed Replace Variables dialog

Inserted code

Hopefully this little tutorial helps you become more efficient with Eclipse. Happy coding!

Posted by Dan | Comments (0) | Add Comment | Permalink

10:29 AM

Getting Moving Again...

Things have been rough on the work front lately, but I'm starting to finally move forward again. It's been about 6 months since I've actually built anything worth mentioning, and I'm finally starting to get back into it :)

So today I'm working on a top secret app using ColdBox, ColdSpring, and Transfer, the super trifecta of ColdFusion development (that's my own personal opinion, your mileage may vary) and I'm starting to get the hang of it. I'm doing all of this development locally on my Mac using a VMWare installation of Windows Server 2003 and SQL Server 2005 with Eclipse as my development IDE of choice.

As I move forward, I'm hoping to have the time to post some of my thoughts here on how it all fits together. I've done lots of OO programming over the last two years, but nothing quite like the "pure" MVC that ColdBox and the rest of the frameworks work within. I've generally developed with a View and a Model, but never with the controller in the middle. The new app I'm working on will have external non-CF clients that will need access to the model and a completely different set of views, so I think this is really going to take my development skills to the next level.

So as I move forward, my sincere thanks (already) to Luis Majano and Mark Mandel for all the work they do in both building and supporting their frameworks.

Posted by Dan | Comments (0) | Add Comment | Permalink

 

Thursday, November 01, 2007

5:39 PM

I'm a Godfather

My girlfriend's ex-husband's girlfriend had a brand spankin' new baby today at 6:31. Isabella Johanna Buraglia is 8 pounds, 5 ounces, and 19 1/2 inches long. I'll be booking our trip to The Springer Show soon :).

Posted by Dan | Comments (4) | Add Comment | Permalink

Comment from sumer on 11/19/2007
Hey that sounds like my life!!! That's awesome, congratulations.

<reply>
Thanks Cuz.
</reply>

Comment from rbw1 on 1/17/2008
Well, congratulations! I'm a godmother myself - it's a great thing to be

<reply>
:)
</reply>

Comment from Cornel on 2/20/2008
Congratualtions to both you and a Angela...

<reply>
Thanks Cornel :)
</reply>

Comment from sean on 5/2/2008
Congratulations! Babies are awesome.

<reply>
They're fantastical little creatures...
</reply>

 

Tuesday, January 09, 2007

6:27 AM

THE BLINK TAG SURVIVES!!!

BOOYAH!

Posted by Dan | Comments (9) | Add Comment | Permalink

Comment from Eric Meyer on 1/9/2007
Okay, I give up. What the hell are you talking about?

<reply>
Your browser is obviously not of the same caliber if it can't display the <blink> tag... sheesh...
</reply>

Comment from Scott on 1/9/2007
Damn! And just when you thought it was safe to surf the web... ;-)

<reply>
:)
</reply>

Comment from andrew on 1/20/2007
pwn list
-----------
[X] Central Texas Regional Mobility Authority

<reply>
lol...
</reply>

Comment from R P on 1/22/2007
I am trying to mod a cdrom driver so it will make the the cd's red from the outside in. the file I need to mod is all in bin. at one point it's on all 108 positions in the string. any help decoding and recoding the file when I an finished would be appreachited.

<reply>
um, okay???
</reply>

Comment from Vhadakhan on 1/26/2007
ROFL

Comment from Keukens on 2/19/2007
But is it a good thing…?
Blinking stuff just freaks me out

Comment from Scott D on 3/2/2007
I just wanted to thank you and the Lynda.com staff for all the hard work. I started building a coldfusion site with cartweaver and had the support of you guys to help me along. Also, I know you probably can't say 'don't use this company' but a word to anyone who wants to try and save a buck with hosting companies... don't! I wound up moving everything over to CrystalTech and now things run outstanding. I have since decided to learn more coldfusion and get my hands dirty with code again.

Comment from Gernot on 5/10/2007
I know this is a dead post but here's my tribute to the blink tag. http://dbacademy.org It's not pure however, I used css.

<reply>
:)
</reply>

Comment from Collins on 7/10/2007
It's been fun using your tutorial on building an ASP web blog. Thanks a million for your wisdom and inspiration

<reply>
You're quite welcome...
</reply>

 

Thursday, January 04, 2007

1:40 PM

"Not of type numeric" when it damn well is....

I have a problem, and it's ColdFusion... We're working on some complex object interaction, and moving data in and out of our objects. Part of the "moving in" part involves building out a structure of arguments based on query columns, and then passing them all in via the ArgumentCollection. Unfortunately, ColdFusion doesn't love us here at lynda.com... It's pitching a fit and saying that our IDs aren't of type numeric, when I know damn well that they are (grumble grumble)...

To demonstrate my point I've come up with the following code example. This fails every time for me:


<!--- Get a query ---<>
<cfset rs = QueryNew("ID,FirstName", "integer,varchar") /<>
<cfset QueryAddRow(rs) /<>
<cfset QuerySetCell(rs, "ID", 3) /<>
<cfset QuerySetCell(rs, "FirstName", "Daniel") /<>

<cfset TestStruct = StructNew() /<>
<cfloop list="#rs.ColumnList#" index="col"<>
	<cfset TestStruct[col] = rs[col] /<>
</cfloop<>

<cfdump var="#TestStruct#" /<>

<!--- Pass the newly created struct into the object to run each setter ---<>
<cfset MyObject = CreateObject("component", "cfcs.test").init(ArgumentCollection = TestStruct) /<>

<cfdump var="#MyObject.getSnapShot()#" /<>

That generates the following error:

The argument ID passed to function init() is not of type numeric.

Has anyone else come across this same error? Is there some hotfix that fixes this? It's completely stymied our development... The only way around it is to set our arguments to accept type="any", which honestly is unacceptable...

Posted by Dan | Comments (7) | Add Comment | Permalink

Comment from charlie griefer on 1/4/2007


add the [1] inside the loop where you're converting the query to a struct.

otherwise, do some dumps on the rs[col] values. output the value of isSimpleValue(rs[col]) for each loop iteration. they're not simple values.

i'm not sure what they are...i thought omitting the [1] would default to the first row...but something more is going on.

in any event, specifying the record position in the query seems to resolve it.

hope that helps.

<reply>
Yup
</reply>

Comment from Danilo on 1/4/2007
Hey man, hope all is well!

My first thought was that the query cell value that is returned is actually some Java data type, not the integer you're telling it to be.

So I tried dumping:
IsNumeric(TestStruct["ID"])
and it output NO so CF wasn't seeing it as numeric. So I thought instead of using the default for pulling the query row value: rs[col] trying rs[col][1] to indicate pulling the first row and then IsNumeric(TestStruct["ID"]) did return YES.

As I don't have access to your CFC...or do I? :-) you'll have to try it to see how it'll work for your situation.

Let me know.

PS: Not that I post here so much, but how about making the textarea a little wider and taller?


<reply>
Nail, meet hammer :)
</reply>

Comment from Adrian J. Moreno on 1/5/2007
I'd say the problem is that ArgumentCollection is an attribute of cfinvoke and (without seeing the code for test.cfc) not an argument of the init() method.

I imagine that init() has two arguments:

{cfargument name="ID" type="numeric" required="true" /}
{cfargument name="FirstName" type="string" required="true" /}

Since you're passing in a named argument called ArgumentCollection and no named argument called ID, the error is thrown as expected.

If you instead use

{cfset MyObject = CreateObject("component", "test").init(ID = TestStruct.ID, FirstName = TestStruct.FirstName) /}

the object will be created correctly.

HTH

<reply>
Actually the argumentcollection allows you to pass in an entire struct of arguments without having to name them all :). It came down to me not referencing the proper row of the recordset.
</reply>

Comment from TAmi on 1/6/2007
Hi Dan...
I have had the same issue before, but I am surprised you are able to CFDUMP an CFC object. I can never get my CFMX to play nice. I usually have to


then


My CFMX is persnickety about trying to evaluate complex structures that involve CFC calls....

Just a thought...
Tami

<reply>
Interesting issue... not sure what would be going on there...
</reply>

Comment from DAD on 1/6/2007
I think that if you turn your = sign over, then take a backward < sign and turn it around to make a >, then take and flip your [ right side up, then leave all the comma's where they are, it ought to work perfectly.
Hope this helps,
Dad

<reply>
Thanks dad, that worked perfectly :).
</reply>

Comment from Paul on 1/8/2007
You are using cfmx6 correct? If so this is a known bug and you may be able to get around it by using the javaCast function when setting the id. In general when you create or edit a query in cfmx6 you may have problems when checking the type of the data.

<reply>
Actually it turned out to be me not referencing the column correctly. I needed this:

<cfset TestStruct[col] = rs[col][1] />
</reply>

Comment from Bryan Ashcraft on 1/15/2007
Total shot in the dark here, but could be the way you are addressing the value? For instance: arguments.testStruct.id vs arguments.testStruct[1]

<reply>
Yep, you got it Bryan...
</reply>

 

Sunday, October 29, 2006

7:26 PM

Ant, Eclipse, and FTP

I'm having an absolute bear of a time getting Eclipse to play nicely with Subversion, Eclipse, and an Ant build file. One of the wonderful things about working with Dreamweaver is the great FTP integration. I can upload, download, all that wonderful stuff, with a single keyboard shortcut directly in the IDE. I'm not having any such luck with Eclipse.

I think the problem is that I'm not only needing FTP access, I also need Subversion/Subclipse integration. It's my understanding that I can "import" from an FTP site and I forever have a connection through the Team plugins. Unfortunately, I need to "import" from a Subversion repository in order to keep things up to date that way. This makes it damn impossible to use any sort of built in FTP integration inside Eclipse.

To try and get around this I've been playing with Ant (thanks Jared) and build.xml files. The hope is that I can create an Autobuild file that will upload a file any time it's created or changed (I'm not ambitious enough yet to tackle file deletions, bear with me here). Unfortunately, the only thing I've (that means Jared) been able to find is the "depends" attribute of the <target> tag. Unfortunately, this also doesn't seem to work worth a damn... It always uploads the entire project any time a single file changes. The depends attribute isn't checking to see whether anything is newer or not.

The most frustrating part of all of this is trying to find good documentation on complex processes. I've spent several hours on google digging through blog posts, forums, Ant documentation and trying to download jar files, write build scripts, and rebuild workspaces, and nothing seems to work as you'd expect. It seems you need to have a greybeard Java developer looking over your shoulder in order to use Ant, or make it do anything you really want it to.

Can someone prove me wrong, and help me figure out how I can make Eclipse just upload a file when I save it? Is that so much to ask? Please???

Posted by Dan | Comments (3) | Add Comment | Permalink

Comment from Keith Peters on 10/29/2006
Sounds like you are off base with depends. That means that one target depends on another target. So targetA is called. It depends on targetB. So targetB is run first. When B is dnoe, then A can run.

<reply>
Gotcha, in that case I got it all wrong :)
</reply>

Comment from Brooks Andrus on 10/29/2006
I believe you're trying to use the selector which is a selector of the core type "fileset". Here's what' the docs say about :

http://ant.apache.org/manual/CoreTypes/selectors.html#dependselect

As far as ftp goes, I'd go ahead and use the scp task (Ant docs tell you where to download the dependencies).

I've had no problems only uploading "changed" files using and scp.

...Hope this helps :)

Comment from Emmanuel Okyere on 10/30/2006
unless i don't really get you, i'll assume what you are looking for are:

svn update (up), svn add, svn commit (ci)

you normally don't want to automate your commits, as you shd normally add meaningful messages per commit

and a depends attribute simply means the listed targets should be executed before the target in context, so i'm not sure how that applies here.

cheers,
-- eokyere :)

<reply>
No, I don't want to automatically commit changes. I want to automatically upload them to a remote server while I'm developing, and then I'll manually Commit files when I'm done on the development server.

Dan
</reply>

 
All images, programming and all that other jazz are Copyright © Daniel Short 2002-2008, unless otherwise noted in the source code.

Dan's generally a slacker, but when he's not, he works at Web Shorts Site Design and deals with feature creep at DWfaq.com.
Now Playing

The last ten songs played in iTunes. If the list is empty, then the tunes aren't on (how sad).

Uncle Kracker

Double Wide

Better Days
CD Cover

ALO

Roses & Clover (Bonus Track Version)

Lady Loop
CD Cover

Now Playing

Listed on BlogShares