{"action":"created","comment":{"url":"https://api.github.com/repos/openshift/origin/pulls/comments/40326754","id":40326754,"diff_hunk":"@@ -0,0 +1,381 @@\n+package cmd\n+\n+import (\n+\t\"bytes\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"os\"\n+\t\"os/exec\"\n+\t\"path/filepath\"\n+\t\"strings\"\n+\n+\t\"github.com/golang/glog\"\n+\t\"github.com/spf13/cobra\"\n+\t\"gopkg.in/pipe.v2\"\n+\tkclient \"k8s.io/kubernetes/pkg/client\"\n+\tkubecmd \"k8s.io/kubernetes/pkg/kubectl/cmd\"\n+\tkcmdutil \"k8s.io/kubernetes/pkg/kubectl/cmd/util\"\n+\n+\t\"github.com/openshift/origin/pkg/cmd/util/clientcmd\"\n+)\n+\n+const (\n+\t// RsyncRecommendedName is the recommended name for the rsync command\n+\tRsyncRecommendedName = \"rsync\"\n+\n+\trsyncLong = `\n+Copy local files to a container\n+\n+This command will attempt to copy local files to a remote container. It will default to the\n+first container if none is specified, and will attempt to use 'rsync' if available locally and in the\n+container. If not present, it will attempt to use 'tar' to send files to the container.`\n+\n+\trsyncExample = `\n+  // Syncrhonize a local directory with a pod directory\n+  $ %[1]s POD ./local/dir/ /remote/dir`\n+\n+\tdefaultRsyncExecutable = \"rsync\"\n+\tdefaultTarExecutable   = \"tar\"\n+)\n+\n+var (\n+\ttestRsyncCommand = []string{\"rsync\", \"--version\"}\n+\ttestTarCommand   = []string{\"tar\", \"--version\"}\n+)\n+\n+// RsyncOptions holds the options to execute the sync command\n+type RsyncOptions struct {\n+\tNamespace       string\n+\tPodName         string\n+\tContainerName   string\n+\tSource          string\n+\tDestination     string\n+\tRsyncExecutable string\n+\tTarExecutable   string\n+\tRshCommand      string\n+\tQuiet           bool\n+\n+\tOut io.Writer\n+\tErr io.Writer\n+\n+\tLocalExecutor  executor\n+\tRemoteExecutor executor\n+\tPipeExecutor   pipeExecutor\n+}\n+\n+// executor executes commands\n+type executor interface {\n+\tExecute(command []string, in io.Reader, out, err io.Writer) error\n+}\n+\n+// pipeExecutor pipes a sequence of commands\n+type pipeExecutor interface {\n+\tExecute(out, err io.Writer, cmds ...*pipeCommand) error\n+}\n+\n+type pipeCommand struct {\n+\tcommand []string\n+\te       executor\n+}\n+\n+func (c *pipeCommand) Pipe() pipe.Pipe {\n+\treturn func(s *pipe.State) error {\n+\t\ts.AddTask(c)\n+\t\treturn nil\n+\t}\n+}\n+\n+func (c *pipeCommand) Run(s *pipe.State) error {\n+\treturn c.e.Execute(c.command, s.Stdin, s.Stdout, s.Stderr)\n+}\n+\n+func (c *pipeCommand) Kill() {\n+\t// No-op for now\n+}\n+\n+type defaultPipeExecutor struct{}\n+\n+func (*defaultPipeExecutor) Execute(out, errOut io.Writer, cmds ...*pipeCommand) error {\n+\tpipes := []pipe.Pipe{}\n+\tfor _, c := range cmds {\n+\t\tpipes = append(pipes, c.Pipe())\n+\t}\n+\tp := pipe.Line(pipes...)\n+\toutBuf, errBuf, err := pipe.DividedOutput(p)\n+\tout.Write(outBuf)\n+\terrOut.Write(errBuf)\n+\treturn err\n+}\n+\n+type defaultLocalExecutor struct{}\n+\n+func (*defaultLocalExecutor) Execute(command []string, in io.Reader, out, errOut io.Writer) error {\n+\tif len(command) < 1 {\n+\t\treturn fmt.Errorf(\"Invalid command\")\n+\t}\n+\tglog.V(5).Infof(\"defaultLocalExecutor executing command: %s\", strings.Join(command, \" \"))\n+\tcmd := exec.Command(command[0], command[1:]...)\n+\tcmd.Stdout = out\n+\tcmd.Stderr = errOut\n+\tcmd.Stdin = in\n+\terr := cmd.Run()\n+\tif err != nil {\n+\t\tglog.V(4).Infof(\"Error from local execution: %v\", err)\n+\t}\n+\treturn err\n+}\n+\n+type defaultRemoteExecutor struct {\n+\tNamespace     string\n+\tPodName       string\n+\tContainerName string\n+\tClient        *kclient.Client\n+\tConfig        *kclient.Config\n+}\n+\n+func (e *defaultRemoteExecutor) Execute(command []string, in io.Reader, out, errOut io.Writer) error {\n+\tglog.V(4).Infof(\"Remote executor running command: %s\", strings.Join(command, \" \"))\n+\texecOptions := &kubecmd.ExecOptions{\n+\t\tIn:            in,\n+\t\tOut:           out,\n+\t\tErr:           errOut,\n+\t\tStdin:         in != nil,\n+\t\tExecutor:      &kubecmd.DefaultRemoteExecutor{},\n+\t\tClient:        e.Client,\n+\t\tConfig:        e.Config,\n+\t\tPodName:       e.PodName,\n+\t\tContainerName: e.ContainerName,\n+\t\tNamespace:     e.Namespace,\n+\t\tCommand:       command,\n+\t}\n+\terr := execOptions.Validate()\n+\tif err != nil {\n+\t\tglog.V(4).Infof(\"Error from remote command validation: %v\", err)\n+\t\treturn err\n+\t}\n+\terr = execOptions.Run()\n+\tif err != nil {\n+\t\tglog.V(4).Infof(\"Error from remote execution: %v\", err)\n+\t}\n+\treturn err\n+}\n+\n+// NewCmdRsync creates a new sync command\n+func NewCmdRsync(name, fullName string, f *clientcmd.Factory, out, errOut io.Writer) *cobra.Command {\n+\to := RsyncOptions{\n+\t\tOut:           out,\n+\t\tErr:           errOut,\n+\t\tLocalExecutor: &defaultLocalExecutor{},\n+\t\tPipeExecutor:  &defaultPipeExecutor{},\n+\t}\n+\tcmd := &cobra.Command{\n+\t\tUse:     fmt.Sprintf(\"%s POD LOCAL_SOURCE REMOTE_DESTINATION\", name),\n+\t\tShort:   \"Copy local files to a pod\",\n+\t\tLong:    rsyncLong,\n+\t\tExample: fmt.Sprintf(rsyncExample, fullName),\n+\t\tRun: func(c *cobra.Command, args []string) {\n+\t\t\tkcmdutil.CheckErr(o.Complete(f, c, args))\n+\t\t\tkcmdutil.CheckErr(o.Validate())\n+\t\t\tkcmdutil.CheckErr(o.Run())\n+\t\t},\n+\t}\n+\n+\tcmd.Flags().StringVarP(&o.ContainerName, \"container\", \"c\", \"\", \"Container within the pod\")\n+\tcmd.Flags().StringVar(&o.RsyncExecutable, \"rsync\", \"\", \"Path to rsync executable\")\n+\tcmd.Flags().StringVar(&o.TarExecutable, \"tar\", \"\", \"Path to tar executable\")\n+\tcmd.Flags().BoolVarP(&o.Quiet, \"quiet\", \"q\", false, \"Quiet copy\")\n+\treturn cmd\n+}\n+\n+// Complete verifies command line arguments and loads data from the command environment\n+func (o *RsyncOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error {\n+\n+\tif len(args) < 3 {\n+\t\treturn kcmdutil.UsageError(cmd, \"POD, LOCAL_SOURCE, and REMOTE_DESTINATION are required arguments\")\n+\t}\n+\tif len(args) > 3 {\n+\n+\t}\n+\to.PodName = args[0]\n+\to.Source = args[1]\n+\to.Destination = args[2]\n+\n+\trsh := siblingCommand(cmd, \"rsh\")\n+\trshCmd := []string{rsh, o.PodName}\n+\tif len(o.ContainerName) > 0 {\n+\t\trshCmd = append(rshCmd, \"-c\", o.ContainerName)\n+\t}\n+\trshCmd = append(rshCmd, \"sh\", \"-c\", \"'exec \\\"$@\\\"'\")","path":"pkg/cmd/cli/cmd/rsync.go","position":null,"original_position":208,"commit_id":"a73e933daac4059375cdd8745d1450e0cf4b60b9","original_commit_id":"dd060d96bd452cb18d82a72226b30dcee36cc6f1","user":{"login":"csrwng","id":5834976,"avatar_url":"https://avatars.githubusercontent.com/u/5834976?v=3","gravatar_id":"","url":"https://api.github.com/users/csrwng","html_url":"https://github.com/csrwng","followers_url":"https://api.github.com/users/csrwng/followers","following_url":"https://api.github.com/users/csrwng/following{/other_user}","gists_url":"https://api.github.com/users/csrwng/gists{/gist_id}","starred_url":"https://api.github.com/users/csrwng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/csrwng/subscriptions","organizations_url":"https://api.github.com/users/csrwng/orgs","repos_url":"https://api.github.com/users/csrwng/repos","events_url":"https://api.github.com/users/csrwng/events{/privacy}","received_events_url":"https://api.github.com/users/csrwng/received_events","type":"User","site_admin":false},"body":"It is using rsh:\r\n\r\n```\r\nrsync -av -e \"oc rsh <podname> sh -c 'exec \"\\$@\" ' \" /tmp/source ignore:/tmp/dest\r\n```","created_at":"2015-09-24T14:45:14Z","updated_at":"2015-09-24T14:45:14Z","html_url":"https://github.com/openshift/origin/pull/4787#discussion_r40326754","pull_request_url":"https://api.github.com/repos/openshift/origin/pulls/4787","_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments/40326754"},"html":{"href":"https://github.com/openshift/origin/pull/4787#discussion_r40326754"},"pull_request":{"href":"https://api.github.com/repos/openshift/origin/pulls/4787"}}},"pull_request":{"url":"https://api.github.com/repos/openshift/origin/pulls/4787","id":45904742,"html_url":"https://github.com/openshift/origin/pull/4787","diff_url":"https://github.com/openshift/origin/pull/4787.diff","patch_url":"https://github.com/openshift/origin/pull/4787.patch","issue_url":"https://api.github.com/repos/openshift/origin/issues/4787","number":4787,"state":"open","locked":false,"title":"Add oc rsync command","user":{"login":"csrwng","id":5834976,"avatar_url":"https://avatars.githubusercontent.com/u/5834976?v=3","gravatar_id":"","url":"https://api.github.com/users/csrwng","html_url":"https://github.com/csrwng","followers_url":"https://api.github.com/users/csrwng/followers","following_url":"https://api.github.com/users/csrwng/following{/other_user}","gists_url":"https://api.github.com/users/csrwng/gists{/gist_id}","starred_url":"https://api.github.com/users/csrwng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/csrwng/subscriptions","organizations_url":"https://api.github.com/users/csrwng/orgs","repos_url":"https://api.github.com/users/csrwng/repos","events_url":"https://api.github.com/users/csrwng/events{/privacy}","received_events_url":"https://api.github.com/users/csrwng/received_events","type":"User","site_admin":false},"body":"Refactors existing rsh command to match upstream structure. Adds rsync command that will use 'rsync' if available and on Linux, otherwise will fall back to 'tar'.\r\n\r\nIn windows, it will use 'tar' and not try rsync.","created_at":"2015-09-24T14:36:58Z","updated_at":"2015-09-24T14:45:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4047276d139d8ff4dcabe2eb6b0741305371e14d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openshift/origin/pulls/4787/commits","review_comments_url":"https://api.github.com/repos/openshift/origin/pulls/4787/comments","review_comment_url":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openshift/origin/issues/4787/comments","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/a73e933daac4059375cdd8745d1450e0cf4b60b9","head":{"label":"csrwng:oc_rsync","ref":"oc_rsync","sha":"a73e933daac4059375cdd8745d1450e0cf4b60b9","user":{"login":"csrwng","id":5834976,"avatar_url":"https://avatars.githubusercontent.com/u/5834976?v=3","gravatar_id":"","url":"https://api.github.com/users/csrwng","html_url":"https://github.com/csrwng","followers_url":"https://api.github.com/users/csrwng/followers","following_url":"https://api.github.com/users/csrwng/following{/other_user}","gists_url":"https://api.github.com/users/csrwng/gists{/gist_id}","starred_url":"https://api.github.com/users/csrwng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/csrwng/subscriptions","organizations_url":"https://api.github.com/users/csrwng/orgs","repos_url":"https://api.github.com/users/csrwng/repos","events_url":"https://api.github.com/users/csrwng/events{/privacy}","received_events_url":"https://api.github.com/users/csrwng/received_events","type":"User","site_admin":false},"repo":{"id":23592505,"name":"origin","full_name":"csrwng/origin","owner":{"login":"csrwng","id":5834976,"avatar_url":"https://avatars.githubusercontent.com/u/5834976?v=3","gravatar_id":"","url":"https://api.github.com/users/csrwng","html_url":"https://github.com/csrwng","followers_url":"https://api.github.com/users/csrwng/followers","following_url":"https://api.github.com/users/csrwng/following{/other_user}","gists_url":"https://api.github.com/users/csrwng/gists{/gist_id}","starred_url":"https://api.github.com/users/csrwng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/csrwng/subscriptions","organizations_url":"https://api.github.com/users/csrwng/orgs","repos_url":"https://api.github.com/users/csrwng/repos","events_url":"https://api.github.com/users/csrwng/events{/privacy}","received_events_url":"https://api.github.com/users/csrwng/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/csrwng/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":true,"url":"https://api.github.com/repos/csrwng/origin","forks_url":"https://api.github.com/repos/csrwng/origin/forks","keys_url":"https://api.github.com/repos/csrwng/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/csrwng/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/csrwng/origin/teams","hooks_url":"https://api.github.com/repos/csrwng/origin/hooks","issue_events_url":"https://api.github.com/repos/csrwng/origin/issues/events{/number}","events_url":"https://api.github.com/repos/csrwng/origin/events","assignees_url":"https://api.github.com/repos/csrwng/origin/assignees{/user}","branches_url":"https://api.github.com/repos/csrwng/origin/branches{/branch}","tags_url":"https://api.github.com/repos/csrwng/origin/tags","blobs_url":"https://api.github.com/repos/csrwng/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/csrwng/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/csrwng/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/csrwng/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/csrwng/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/csrwng/origin/languages","stargazers_url":"https://api.github.com/repos/csrwng/origin/stargazers","contributors_url":"https://api.github.com/repos/csrwng/origin/contributors","subscribers_url":"https://api.github.com/repos/csrwng/origin/subscribers","subscription_url":"https://api.github.com/repos/csrwng/origin/subscription","commits_url":"https://api.github.com/repos/csrwng/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/csrwng/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/csrwng/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/csrwng/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/csrwng/origin/contents/{+path}","compare_url":"https://api.github.com/repos/csrwng/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/csrwng/origin/merges","archive_url":"https://api.github.com/repos/csrwng/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/csrwng/origin/downloads","issues_url":"https://api.github.com/repos/csrwng/origin/issues{/number}","pulls_url":"https://api.github.com/repos/csrwng/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/csrwng/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/csrwng/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/csrwng/origin/labels{/name}","releases_url":"https://api.github.com/repos/csrwng/origin/releases{/id}","created_at":"2014-09-02T19:29:25Z","updated_at":"2015-05-08T12:59:09Z","pushed_at":"2015-09-24T14:40:17Z","git_url":"git://github.com/csrwng/origin.git","ssh_url":"git@github.com:csrwng/origin.git","clone_url":"https://github.com/csrwng/origin.git","svn_url":"https://github.com/csrwng/origin","homepage":"https://openshift.github.io","size":141624,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"openshift:master","ref":"master","sha":"2c5d39ef9421f1f8dcde2b760178365071fd895f","user":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"repo":{"id":22442668,"name":"origin","full_name":"openshift/origin","owner":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openshift/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":false,"url":"https://api.github.com/repos/openshift/origin","forks_url":"https://api.github.com/repos/openshift/origin/forks","keys_url":"https://api.github.com/repos/openshift/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openshift/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openshift/origin/teams","hooks_url":"https://api.github.com/repos/openshift/origin/hooks","issue_events_url":"https://api.github.com/repos/openshift/origin/issues/events{/number}","events_url":"https://api.github.com/repos/openshift/origin/events","assignees_url":"https://api.github.com/repos/openshift/origin/assignees{/user}","branches_url":"https://api.github.com/repos/openshift/origin/branches{/branch}","tags_url":"https://api.github.com/repos/openshift/origin/tags","blobs_url":"https://api.github.com/repos/openshift/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openshift/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openshift/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/openshift/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/openshift/origin/languages","stargazers_url":"https://api.github.com/repos/openshift/origin/stargazers","contributors_url":"https://api.github.com/repos/openshift/origin/contributors","subscribers_url":"https://api.github.com/repos/openshift/origin/subscribers","subscription_url":"https://api.github.com/repos/openshift/origin/subscription","commits_url":"https://api.github.com/repos/openshift/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/openshift/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/openshift/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/openshift/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/openshift/origin/contents/{+path}","compare_url":"https://api.github.com/repos/openshift/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openshift/origin/merges","archive_url":"https://api.github.com/repos/openshift/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openshift/origin/downloads","issues_url":"https://api.github.com/repos/openshift/origin/issues{/number}","pulls_url":"https://api.github.com/repos/openshift/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/openshift/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/openshift/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openshift/origin/labels{/name}","releases_url":"https://api.github.com/repos/openshift/origin/releases{/id}","created_at":"2014-07-30T20:04:05Z","updated_at":"2015-09-24T10:01:12Z","pushed_at":"2015-09-24T14:44:12Z","git_url":"git://github.com/openshift/origin.git","ssh_url":"git@github.com:openshift/origin.git","clone_url":"https://github.com/openshift/origin.git","svn_url":"https://github.com/openshift/origin","homepage":"http://www.openshift.org","size":244517,"stargazers_count":696,"watchers_count":696,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":423,"mirror_url":null,"open_issues_count":567,"forks":423,"open_issues":567,"watchers":696,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/4787"},"html":{"href":"https://github.com/openshift/origin/pull/4787"},"issue":{"href":"https://api.github.com/repos/openshift/origin/issues/4787"},"comments":{"href":"https://api.github.com/repos/openshift/origin/issues/4787/comments"},"review_comments":{"href":"https://api.github.com/repos/openshift/origin/pulls/4787/comments"},"review_comment":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openshift/origin/pulls/4787/commits"},"statuses":{"href":"https://api.github.com/repos/openshift/origin/statuses/a73e933daac4059375cdd8745d1450e0cf4b60b9"}}}}