@@ -34,6 +34,7 @@ func setPassword(userInfo *url.Userinfo, password string) *url.Userinfo {
3434
3535type UrlJson struct {
3636 Scheme string `json:"scheme"`
37+ Hostname string `json:"hostname"`
3738 Host string `json:"host"`
3839 Port string `json:"port"`
3940 Path string `json:"path"`
@@ -45,10 +46,17 @@ type UrlJson struct {
4546 Params map [string ][]string `json:"params,omitempty"`
4647}
4748
48- func toJson (theUrl * url.URL ) string {
49+ func toJson (theUrl * url.URL , pretty bool ) string {
50+ var theHost string
51+ if theUrl .Port () != "" {
52+ theHost = fmt .Sprintf ("%s:%s" , theUrl .Hostname (), theUrl .Port ())
53+ } else {
54+ theHost = theUrl .Hostname ()
55+ }
4956 urlJson := UrlJson {
5057 Scheme : theUrl .Scheme ,
51- Host : theUrl .Hostname (),
58+ Hostname : theUrl .Hostname (),
59+ Host : theHost ,
5260 Port : theUrl .Port (),
5361 Path : theUrl .Path ,
5462 Query : theUrl .RawQuery ,
@@ -63,7 +71,13 @@ func toJson(theUrl *url.URL) string {
6371 urlJson .Password = password
6472 }
6573 }
66- jsonStr , err := json .Marshal (urlJson )
74+ var jsonStr []byte
75+ var err error
76+ if pretty {
77+ jsonStr , err = json .MarshalIndent (urlJson , "" , " " )
78+ } else {
79+ jsonStr , err = json .Marshal (urlJson )
80+ }
6781 if err != nil {
6882 fmt .Fprintf (os .Stderr , "ERROR: unable to marshal URL to JSON: %v\n " , err )
6983 os .Exit (1 )
@@ -77,14 +91,32 @@ var helpText = `urly: A URL parsing and processing tool.`
7791func main () {
7892
7993 var scheme = pflag .String ("scheme" , "" , "Set the URL scheme" )
94+ var noScheme = pflag .Bool ("no-scheme" , false , "Remove the URL scheme" )
95+
96+ var envUsername = pflag .String ("username-env" , "" , "Environment variable containing the username for URL processing" )
97+ var textUsername = pflag .String ("username" , "" , "Username for URL processing" )
98+ var noUsername = pflag .Bool ("no-username" , false , "Remove the username from the URL" )
99+
80100 var envPassword = pflag .String ("password-env" , "" , "Environment variable containing the password for URL processing" )
81101 var stdinPassword = pflag .Bool ("password-stdin" , false , "Read password from standard input" )
102+ var noPassword = pflag .Bool ("no-password" , false , "Remove the password from the URL" )
103+
104+ var hostname = pflag .String ("hostname" , "" , "Set the URL hostname" )
105+ var noHostname = pflag .Bool ("no-hostname" , false , "Remove the URL hostname" )
106+ var port = pflag .String ("port" , "" , "Set the URL port" )
107+ var noPort = pflag .Bool ("no-port" , false , "Remove the URL port" )
108+ var path = pflag .String ("path" , "" , "Set the URL path" )
109+ var noPath = pflag .Bool ("no-path" , false , "Remove the URL path" )
110+ var query = pflag .String ("query" , "" , "Set the URL query" )
111+ var noQuery = pflag .Bool ("no-query" , false , "Remove the URL query" )
112+ var fragment = pflag .String ("fragment" , "" , "Set the URL fragment" )
113+ var noFragment = pflag .Bool ("no-fragment" , false , "Remove the URL fragment" )
114+
82115 var envUrl = pflag .String ("url-env" , "" , "Environment variable containing the URL to process" )
83- var envUsername = pflag .String ("username-env" , "" , "Environment variable containing the username for URL processing" )
84- var textUsername = pflag .String ("username" , "" , "Username for URL processing" )
85- //LATER: var format = pflag.String("format", "text", "Output format: text or json")
116+
86117 var output = pflag .String ("output" , "url" , "Output type: url, scheme, host, port, path, query, fragment, userinfo, username, password" )
87118 var newline = pflag .Bool ("newline" , false , "Append newline to output" )
119+
88120 var help = pflag .Bool ("help" , false , "Detailed help" )
89121 var version = pflag .Bool ("version" , false , "Version info" )
90122
@@ -96,7 +128,10 @@ func main() {
96128 }
97129
98130 if * help {
99- fmt .Printf ("%s\n " , helpText )
131+ fmt .Println ("urly - manipulate URLs" )
132+ pflag .PrintDefaults ()
133+ fmt .Println ()
134+ fmt .Println ("Use `man urly` for detailed help." )
100135 return
101136 }
102137
@@ -128,13 +163,35 @@ func main() {
128163 theUrl = & url.URL {}
129164 }
130165
131- if * envUsername != "" {
166+ if * noScheme {
167+ theUrl .Scheme = ""
168+ } else if * scheme != "" {
169+ theUrl .Scheme = * scheme
170+ }
171+
172+ if * noUsername {
173+ if theUrl .User != nil {
174+ thePassword , hasPassword := theUrl .User .Password ()
175+ if hasPassword {
176+ theUrl .User = url .UserPassword ("" , thePassword )
177+ } else {
178+ theUrl .User = nil
179+ }
180+ }
181+ } else if * envUsername != "" {
132182 theUrl .User = setUserName (theUrl .User , os .Getenv (* envUsername ))
133183 } else if * textUsername != "" {
134184 theUrl .User = setUserName (theUrl .User , * textUsername )
135185 }
136186
137- if * envPassword != "" {
187+ if * noPassword {
188+ if theUrl .User != nil {
189+ theUsername := theUrl .User .Username ()
190+ theUrl .User = url .User (theUsername )
191+ } else {
192+ theUrl .User = nil
193+ }
194+ } else if * envPassword != "" {
138195 theUrl .User = setPassword (theUrl .User , os .Getenv (* envPassword ))
139196 } else if * stdinPassword {
140197 var password string
@@ -146,10 +203,50 @@ func main() {
146203 theUrl .User = setPassword (theUrl .User , password )
147204 }
148205
149- if * scheme != "" {
206+ if * noScheme {
207+ theUrl .Scheme = ""
208+ } else if * scheme != "" {
150209 theUrl .Scheme = * scheme
151210 }
152211
212+ if * noHostname {
213+ if theUrl .Port () != "" {
214+ theUrl .Host = ":" + theUrl .Port ()
215+ } else {
216+ theUrl .Host = ""
217+ }
218+ } else if * hostname != "" {
219+ if theUrl .Port () != "" {
220+ theUrl .Host = * hostname + ":" + theUrl .Port ()
221+ } else {
222+ theUrl .Host = * hostname
223+ }
224+ }
225+
226+ if * noPort {
227+ theUrl .Host = theUrl .Hostname ()
228+ } else if * port != "" {
229+ theUrl .Host = fmt .Sprintf ("%s:%s" , theUrl .Hostname (), * port )
230+ }
231+
232+ if * noPath {
233+ theUrl .Path = ""
234+ } else if * path != "" {
235+ theUrl .Path = * path
236+ }
237+
238+ if * noQuery {
239+ theUrl .RawQuery = ""
240+ } else if * query != "" {
241+ theUrl .RawQuery = * query
242+ }
243+
244+ if * noFragment {
245+ theUrl .Fragment = ""
246+ } else if * fragment != "" {
247+ theUrl .Fragment = * fragment
248+ }
249+
153250 switch * output {
154251 case "url" :
155252 fmt .Println (theUrl .String ())
@@ -186,7 +283,9 @@ func main() {
186283 }
187284 }
188285 case "json" :
189- fmt .Print (toJson (theUrl ))
286+ fmt .Print (toJson (theUrl , true ))
287+ case "jsonl" :
288+ fmt .Print (toJson (theUrl , false ))
190289 default :
191290 fmt .Fprintf (os .Stderr , "ERROR: Unknown output type: %s\n " , * output )
192291 os .Exit (1 )
0 commit comments