Wallace Kelly

writes about F#, WPF, async, and the like.

Script for adding and removing the ClickOnce .deploy extension

I was recently debugging a ClickOnce deployment. I needed a way to quickly add and remove the *.deploy extension from all the files in a deployment folder. Well, not all the files. The *.manifest file is treated differently. Here is the F# script that I used.

 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: 
open System
open System.IO

let args = fsi.CommandLineArgs

let showUsage() = 
    printfn "Usage: fsi.exe DeployExtension -- Dir Cmd"
    printfn "       where Dir is the name of the application directory"
    printfn "         and Cmd is either 'Add' or 'Remove'"

match args.Length with
| 4 -> 
    let dir = args.[2]
    let cmd = args.[3]
    printfn "%s the deploy extension to '%s'? " cmd dir
    match Console.ReadKey(true).Key with
    | ConsoleKey.Y -> 
        for f in Directory.EnumerateFiles dir do
            let ext = Path.GetExtension(f)
            match cmd.ToLower() with
            | "add" -> 
                match ext with
                | ".deploy" | ".manifest" -> ()
                | _ -> 
                    printfn "Adding deploy extension to %s" f
                    File.Move(f, sprintf "%s.deploy" f)
            | "remove" -> 
                match ext with
                | ".deploy" -> 
                    printfn "Removing deploy extension from %s" f
                    File.Move(f, (Path.ChangeExtension(f, null)))
                | _ -> ()
            | _ -> showUsage()
    | _ -> ()
| _ -> showUsage()
namespace System
namespace System.IO
val args : string []

Full name: scriptforaddingandremovingtheclickoncedeployextension.args
val fsi : Compiler.Interactive.InteractiveSession

Full name: Microsoft.FSharp.Compiler.Interactive.Settings.fsi
property Compiler.Interactive.InteractiveSession.CommandLineArgs: string []
val showUsage : unit -> unit

Full name: scriptforaddingandremovingtheclickoncedeployextension.showUsage
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property Array.Length: int
val dir : string
val cmd : string
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.ReadKey() : ConsoleKeyInfo
Console.ReadKey(intercept: bool) : ConsoleKeyInfo
type ConsoleKey =
  | Backspace = 8
  | Tab = 9
  | Clear = 12
  | Enter = 13
  | Pause = 19
  | Escape = 27
  | Spacebar = 32
  | PageUp = 33
  | PageDown = 34
  | End = 35
  ...

Full name: System.ConsoleKey
field ConsoleKey.Y = 89
val f : string
type Directory =
  static member CreateDirectory : path:string -> DirectoryInfo + 1 overload
  static member Delete : path:string -> unit + 1 overload
  static member EnumerateDirectories : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFileSystemEntries : path:string -> IEnumerable<string> + 2 overloads
  static member EnumerateFiles : path:string -> IEnumerable<string> + 2 overloads
  static member Exists : path:string -> bool
  static member GetAccessControl : path:string -> DirectorySecurity + 1 overload
  static member GetCreationTime : path:string -> DateTime
  static member GetCreationTimeUtc : path:string -> DateTime
  static member GetCurrentDirectory : unit -> string
  ...

Full name: System.IO.Directory
Directory.EnumerateFiles(path: string) : Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string) : Collections.Generic.IEnumerable<string>
Directory.EnumerateFiles(path: string, searchPattern: string, searchOption: SearchOption) : Collections.Generic.IEnumerable<string>
val ext : string
type Path =
  static val DirectorySeparatorChar : char
  static val AltDirectorySeparatorChar : char
  static val VolumeSeparatorChar : char
  static val InvalidPathChars : char[]
  static val PathSeparator : char
  static member ChangeExtension : path:string * extension:string -> string
  static member Combine : [<ParamArray>] paths:string[] -> string + 3 overloads
  static member GetDirectoryName : path:string -> string
  static member GetExtension : path:string -> string
  static member GetFileName : path:string -> string
  ...

Full name: System.IO.Path
Path.GetExtension(path: string) : string
String.ToLower() : string
String.ToLower(culture: Globalization.CultureInfo) : string
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...

Full name: System.IO.File
File.Move(sourceFileName: string, destFileName: string) : unit
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
Path.ChangeExtension(path: string, extension: string) : string

MAGE.EXE and the Certificate Store

I need to sign a ClickOnce manifest using mage.exe. The certificate is in the Windows Certificate Store. How do I do that?

Read more...

WPF ViewModel of an F# Record

How does one expose an F# record in a WPF view model? My F# code uses immutable records. But, I need to bind those records to a WPF user interface in a view model. What is the right way to do that?

Read more...

Script for adding and removing the ClickOnce .deploy extension

I was recently debugging a ClickOnce deployment. I needed a way to quickly add and remove the *.deploy extension from all the files in a deployment folder. Well, not all the files. The *.manifest file is treated differently.

Read more...

Calculating nice chart axis ranges

I was working on a project that required calculating nice ranges for chart axes. I found a useful discussion here.

Here is what I used in C# and so far it is working adequately.

Read more...

WPF menus that go up

I needed a menu docked to the bottom of an application's window. Docking to the bottom of the window is no problem. However, it did not work well, because by default, WPF menus drop down. I needed it to drop up.

Read more...

Subscribe